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 ( tfield* 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 megaBlitter<ColorTransform_None, ColorMerger_AlphaLighter, SourcePixelSelector_DirectFlip,TargetPixelSelector_All>(getPicture( dir, weather), surface, pos, nullParam, 0.7, flip, nullParam);
00221 } else
00222 if ( displayMethod == 2 ) {
00223 const Surface& s = getPicture( dir, weather);
00224 if ( !s.valid() )
00225 return;
00226
00227 if ( s.GetPixelFormat().BitsPerPixel() == 8 ) {
00228 MegaBlitter< 1,4,
00229 ColorTransform_None,
00230 ColorMerger_Alpha_XLAT_TableShifter,
00231 SourcePixelSelector_DirectFlip,
00232 TargetPixelSelector_All,
00233 ColorConverter_PassThrough
00234 >
00235 blitter;
00236 blitter.setFlipping( flip & 1, flip & 2 );
00237 blitter.blit( s, surface, pos );
00238 }
00239
00240 } else
00241 if ( displayMethod == 4 ) {
00242 const Surface& s = getPicture( dir, weather);
00243 if ( !s.valid() )
00244 return;
00245
00246 if ( dir != 0 && rotateImage ) {
00247 megaBlitter<ColorTransform_None, ColorMerger_AlphaMixer, SourcePixelSelector_CacheRotation ,TargetPixelSelector_All>(s, surface, pos, nullParam,nullParam,make_pair(&s,directionangle[dir%6]),nullParam);
00248 } else {
00249 megaBlitter<ColorTransform_None, ColorMerger_AlphaMixer, SourcePixelSelector_DirectFlip, TargetPixelSelector_All>(s, surface, pos, nullParam,nullParam, flip, nullParam);
00250 }
00251 } else {
00252 bool disp = true;
00253 #ifndef karteneditor
00254 if ( displayMethod == 3 )
00255 disp = false;
00256 #endif
00257 if ( disp ) {
00258 const Surface& s = getPicture( dir, weather);
00259 if ( !s.valid() )
00260 return;
00261 if ( flip ) {
00262
00263 megaBlitter<ColorTransform_None, ColorMerger_AlphaMerge, SourcePixelSelector_DirectFlip,TargetPixelSelector_All>(s, surface, pos, nullParam,nullParam, flip, nullParam);
00264
00265
00266 } else {
00267 if ( dir != 0 && rotateImage ) {
00268
00269 megaBlitter<ColorTransform_None, ColorMerger_AlphaMerge, SourcePixelSelector_CacheRotation ,TargetPixelSelector_All>(s, surface, pos, nullParam,nullParam,make_pair(&s,directionangle[dir%6]),nullParam);
00270
00271
00272 } else {
00273
00274 megaBlitter<ColorTransform_None, ColorMerger_AlphaMerge, SourcePixelSelector_Plain,TargetPixelSelector_All>(s, surface, pos, nullParam,nullParam,nullParam,nullParam);
00275
00276
00277 }
00278 }
00279 }
00280 }
00281 }
00282
00283
00284 void ObjectType :: display ( Surface& surface, const SPoint& pos ) const
00285 {
00286 display ( surface, pos, rotateImage? 0 : 64, 0 );
00287 }
00288
00289
00290
00291
00292 #ifndef converter
00293
00294 namespace ForestCalculation {
00295
00296
00297
00298
00299
00300
00301
00302 const int woodformnum = 28;
00303 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 };
00304
00305
00306 int SmoothTreesData0[] = {
00307 4, 7, 10,101,
00308 1,0x0001,243,
00309 1,0x0115,243,
00310 30,0x3F, 30,243,0x3F, 60,243,0x3F, 39,243,0x3F, 51,243,
00311 0x3F, 28,243,0x3F, 35,243,0x3F, 48,243,0x3F, 6,243,
00312 0x3F, 57,243,0x3F, 15,243,0x3F, 14,243,0x3F, 56,243,
00313 0x3F, 7,243,0x3F, 49,243,0x3F, 47,243,0x3F, 59,243,
00314 0x3F, 31,243,0x3F, 61,243,0x3F, 62,243,0x3F, 55,243,
00315 0x3F, 23,243,0x3F, 46,243,0x3F, 29,243,0x3F, 58,243,
00316 0x3F, 53,243,0x3F, 43,243,0x3F, 22,243,0x3F, 38,243,
00317 0x3F, 50,243,0x3F, 52,243,
00318 7,264,265,266,267,268,269,270
00319 };
00320
00321 int SmoothTreesData[] = {
00322 4, 7, 10,101,
00323 1,0x0001,243,
00324 1,0x0115,243,
00325 30,0x3F, 30,244,0x3F, 60,245,0x3F, 39,246,0x3F, 51,247,
00326 0x3F, 28,248,0x3F, 29,248,0x3F, 35,249,0x3F, 43,249,
00327 0x3F, 48,250,0x3F, 50,250,0x3F, 52,250,0x3F, 6,251,
00328 0x3F, 22,251,0x3F, 38,251,0x3F, 57,252,0x3F, 15,253,
00329 0x3F, 14,254,0x3F, 46,254,0x3F, 56,255,0x3F, 58,255,
00330 0x3F, 7,256,0x3F, 23,256,0x3F, 49,257,0x3F, 53,257,
00331 0x3F, 47,258,0x3F, 59,259,0x3F, 31,260,0x3F, 61,261,
00332 0x3F, 62,262,0x3F, 55,263,
00333 7,264,265,266,267,268,269,270
00334 };
00335
00336 int UnSmoothTreesData[] = {
00337 4, 7, 8, 9,
00338 1,0x011C,243,
00339 0,
00340 0,
00341 1,243
00342 };
00343
00344
00345
00346
00347 int SmoothBanksData [] = {
00348 4, 7, 16, 77,
00349 1, 0x0103, 95,
00350 4, 0x010F, 95,
00351 0x010E, 0,
00352 0x0109,110,
00353 0x0107,121,
00354 20,0x3F,59, 98, 0x3F,51, 98, 0x3F,47, 99, 0x3F,39, 99,
00355 0x3F,31,100, 0x3F,30,100, 0x3F,61,101, 0x3F,60,101,
00356 0x3F,55,102, 0x3F,62,103, 0x3F,35,104, 0x3F,28,105,
00357 0x3F,56,106, 0x3F,48,106, 0x3F,49,106, 0x3F,57,106,
00358 0x3F,14,107, 0x3F,15,107, 0x3F, 7,107, 0x3F, 6,107,
00359 0
00360 };
00361
00362 int UnSmoothBanksData [] = {
00363 4, 7, 8, 9,
00364 1, 0x010C, 98,
00365 0,
00366 0,
00367 1, 95
00368 };
00369
00370
00371 int SmoothDarkBanksData [] = {
00372 4, 7, 16, 77,
00373 1,0x0103,385,
00374 4,0x0103,385,
00375 0x010A,373,
00376 0x0104,449,
00377 0x0104,463,
00378 20,0x3F,59,373, 0x3F,51,373, 0x3F,47,374, 0x3F,39,374,
00379 0x3F,31,375, 0x3F,30,375, 0x3F,61,376, 0x3F,60,376,
00380 0x3F,55,377, 0x3F,62,378, 0x3F,35,379, 0x3F,28,380,
00381 0x3F,56,381, 0x3F,48,381, 0x3F,49,381, 0x3F,57,381,
00382 0x3F,14,382, 0x3F,15,382, 0x3F, 7,382, 0x3F, 6,382,
00383 0
00384 };
00385
00386 int UnSmoothDarkBanksData [] = {
00387 4, 7, 8, 9,
00388 1,0x010A,373,
00389 0,
00390 0,
00391 1,385
00392 };
00393
00394
00395
00396 class Smoothing {
00397 GameMap* actmap;
00398 public:
00399 Smoothing ( GameMap* gamemap ) : actmap ( gamemap ) {};
00400 tfield* getfield ( int x, int y )
00401 {
00402 return actmap->getField ( x, y );
00403 }
00404
00405 int IsInSetOfWord( int Wert, int* A )
00406 {
00407 int Pos = 0;
00408 int Anz1 = A[Pos];
00409 Pos++;
00410 int res = 0;
00411 int Anz2;
00412 while ( Anz1 > 0 ) {
00413 int W = A[Pos];
00414 Pos++;
00415 Anz2 = W & 0xff;
00416
00417 if ( W & 0x100 ) {
00418 if (( Wert>= A[Pos]) && (Wert< A[Pos]+Anz2))
00419 res = 1;
00420 Pos++;
00421 } else {
00422 while ( Anz2 > 0) {
00423 if ( Wert == A[Pos] )
00424 res = 1;
00425 Pos++;
00426 Anz2--;
00427 }
00428 }
00429
00430 Anz1--;
00431 }
00432
00433 return res;
00434 };
00435
00436
00437 int GetNeighbourMask( int x, int y, int* Arr, ObjectType* o )
00438 {
00439 int res = 0;
00440 for ( int d = 0; d < sidenum; d++ ) {
00441 int x1 = x;
00442 int y1 = y;
00443 getnextfield ( x1, y1, d );
00444 tfield* fld = getfield ( x1, y1 );
00445 if ( fld ) {
00446
00447 Object* obj = fld->checkforobject ( o );
00448 if ( obj )
00449 if ( obj->typ->weather.test(0) )
00450 if ( IsInSetOfWord ( obj->typ->weatherPicture[0].bi3pic[ obj->dir ], Arr ))
00451 res += 1 << d;
00452
00453
00454
00455 } else
00456 res += 1 << d;
00457
00458 }
00459 return res;
00460 };
00461
00462 int GetNeighbourMask( int x, int y, int* Arr )
00463 {
00464 int res = 0;
00465 for ( int d = 0; d < sidenum; d++ ) {
00466 int x1 = x;
00467 int y1 = y;
00468 getnextfield ( x1, y1, d );
00469 tfield* fld = getfield ( x1, y1 );
00470 if ( fld ) {
00471
00472 if ( IsInSetOfWord ( fld->typ->bi_pict, Arr ))
00473 res += 1 << d;
00474
00475 } else
00476 res += 1 << d;
00477
00478 }
00479 return res;
00480 };
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498 int SearchAndGetInt( int Wert, int* Arr, int* Res )
00499 {
00500 int Anz = Arr[0];
00501 int Pos = 1;
00502 while ( Anz> 0 ) {
00503 if (( Wert & Arr[Pos]) == Arr[Pos+1] ) {
00504 *Res = Arr[Pos+2];
00505 return Anz > 0;
00506 }
00507 Pos += 3;
00508 Anz--;
00509 }
00510 return Anz> 0;
00511 };
00512
00513
00514 int SmoothIt( ObjectType* TerObj, int* SmoothData )
00515 {
00516 int P0 = SmoothData[0];
00517 int P1 = SmoothData[1];
00518 int P2 = SmoothData[2];
00519 int P3 = SmoothData[3];
00520 int Res = 0;
00521 for ( int Y = 0 ; Y < actmap->ysize; Y++ )
00522 for ( int X = 0; X < actmap->xsize; X++ ) {
00523 if ( TerObj ) {
00524 Object* obj = getfield ( X, Y )-> checkforobject ( TerObj );
00525 if ( obj && obj->typ->weather.test(0) ) {
00526 int Old = obj->dir;
00527
00528
00529 if ( IsInSetOfWord( obj->typ->weatherPicture[0].bi3pic[ obj->dir ], &SmoothData[P0] )) {
00530 int Mask = GetNeighbourMask( X, Y, &SmoothData[P1], TerObj );
00531 if ( Mask < 63 ) {
00532 int nw;
00533 if ( !SearchAndGetInt(Mask, &SmoothData[P2], &nw) ) {
00534 if ( SmoothData[P3] == 0 || SmoothData[P3] == 1 )
00535 nw = SmoothData[P3+ 1];
00536 else
00537 nw = SmoothData[P3+ 1 ];
00538 }
00539 for ( int i = 0; i < TerObj->weatherPicture[0].bi3pic.size(); i++ )
00540 if ( TerObj->weatherPicture[0].bi3pic[ i ] == nw )
00541 obj->dir = i;
00542 }
00543 }
00544 if ( Old != obj->dir )
00545 Res = 1;
00546 }
00547 } else {
00548 tfield* fld = getfield ( X, Y );
00549 TerrainType::Weather* old = fld->typ;
00550
00551
00552 if ( IsInSetOfWord( fld->typ->bi_pict, &SmoothData[P0] )) {
00553 int Mask = GetNeighbourMask( X, Y, &SmoothData[P1] );
00554 if ( Mask < 63 ) {
00555 int nw;
00556 if ( !SearchAndGetInt(Mask, &SmoothData[P2], &nw) ) {
00557 if ( SmoothData[P3] == 0 || SmoothData[P3] == 1 )
00558 nw = SmoothData[P3+ 1];
00559 else
00560 nw = SmoothData[P3+ 1 ];
00561 }
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577 }
00578 }
00579 if ( old != fld->typ )
00580 Res = 1;
00581
00582 }
00583 }
00584 return Res;
00585 };
00586
00587
00588
00589 void smooth ( int what, ObjectType* woodObj )
00590 {
00591 int ShowAgain = 0;
00592 if ( what & 2 ) {
00593 if ( SmoothIt( NULL, UnSmoothBanksData) )
00594 ShowAgain = 1;
00595 if ( SmoothIt( NULL, UnSmoothDarkBanksData) )
00596 ShowAgain = 1;
00597 if ( SmoothIt( NULL, SmoothBanksData) )
00598 ShowAgain = 1;
00599 if ( SmoothIt( NULL, SmoothDarkBanksData) )
00600 ShowAgain = 1;
00601 }
00602
00603 if ( what & 1 ) {
00604 if ( woodObj ) {
00605 int count = 0;
00606 while ( SmoothIt ( woodObj, SmoothTreesData0 ) && count < 20 ) {
00607 ShowAgain = 1;
00608 count++;
00609 }
00610 if ( SmoothIt ( woodObj, SmoothTreesData) )
00611 ShowAgain = 1;
00612 }
00613 }
00614
00615
00616
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 void smooth ( int what, GameMap* gamemap, ObjectType* woodObj )
00749 {
00750 Smoothing s ( gamemap );
00751 s.smooth ( what, woodObj );
00752 }
00753
00754
00755 void calculateforest( GameMap* actmap, ObjectType* woodObj )
00756 {
00757 for ( int y = 0; y < actmap->ysize ; y++)
00758 for ( int x = 0; x < actmap->xsize ; x++) {
00759 tfield* fld = actmap->getField(x,y);
00760
00761 for ( tfield::ObjectContainer::iterator i = fld->objects.begin(); i != fld->objects.end(); i++ )
00762 if ( i->typ == woodObj )
00763 i->dir = 0;
00764 }
00765
00766 Smoothing s ( actmap );
00767 s.smooth( 1, woodObj );
00768 return;
00769
00770 int run = 0;
00771 int changed ;
00772 do {
00773 changed = 0;
00774 for ( int y = 0; y < actmap->ysize ; y++)
00775 for ( int x = 0; x < actmap->xsize ; x++) {
00776 tfield* fld = actmap->getField(x,y);
00777
00778 for ( tfield::ObjectContainer::iterator o = fld->objects.begin(); o != fld->objects.end(); o++ )
00779 if ( o->typ == woodObj ) {
00780 int c = 0;
00781 for ( int i = 0; i < sidenum; i++) {
00782 int a = x;
00783 int b = y;
00784 getnextfield( a, b, i );
00785 tfield* fld2 = actmap->getField(a,b);
00786
00787 if ( fld2 ) {
00788 Object* oi = fld2->checkforobject ( o->typ );
00789 if ( oi )
00790 if ( oi->dir <= 20 || run == 0 )
00791 c |= 1 << i ;
00792 }
00793 }
00794
00795
00796 int dr;
00797 for ( int j = 0; j < woodformnum; j++ )
00798 if ( woodform[j] == c ) {
00799 dr = j;
00800
00801 }
00802
00803
00804
00805
00806 if ( o->dir != dr && !(o->dir >= 21 && dr >= 21)) {
00807 o->dir = dr;
00808 fld->setparams();
00809 changed = 1;
00810 }
00811 }
00812 }
00813 run++;
00814 } while ( changed );
00815 }
00816
00817 }
00818
00819
00820 #else // ifdef converter
00821
00822
00823
00824 #endif
00825
00826
00827 int ObjectType :: getMemoryFootprint() const
00828 {
00829 int size = sizeof( *this );
00830 for ( int ww = 0; ww < cwettertypennum; ww++ ) {
00831 size += for_each( weatherPicture[ww].images.begin(), weatherPicture[ww].images.end(), MemorySum<Surface>() ).size;
00832 size += for_each( weatherPicture[ww].overviewMapImage.begin(), weatherPicture[ww].overviewMapImage.end(), MemorySum<OverviewMapImage>() ).size;
00833 }
00834
00835 return size;
00836 }
00837
00838
00839
00840 const int object_version = 21;
00841
00842 void ObjectType :: read ( tnstream& stream )
00843 {
00844 int version = stream.readInt();
00845
00846 if ( version < 9 )
00847 fatalError ( "sorry, the old file format for objects cannot be loaded any more" );
00848
00849 if ( version <= object_version && version >= 9 ) {
00850
00851 id = stream.readInt();
00852 groupID = stream.readInt();
00853
00854 int ___weather = stream.readInt();
00855 weather.reset();
00856 for ( int i = 0; i < cwettertypennum; i++ )
00857 if ( ___weather & ( 1 << i ))
00858 weather.set ( i );
00859
00860 visibleago = stream.readInt();
00861
00862 if ( version <= 20 ) {
00863 vector<int> IDs;
00864 readClassContainer( IDs, stream );
00865 linkableObjects.clear();
00866 for ( int i = 0; i < IDs.size(); ++i )
00867 linkableObjects.push_back( IntRange(IDs[i]));
00868
00869 readClassContainer( IDs, stream );
00870 linkableTerrain.clear();
00871 for ( int i = 0; i < IDs.size(); ++i )
00872 linkableTerrain.push_back( IntRange(IDs[i]));
00873 } else {
00874 readClassContainer( linkableObjects, stream );
00875 readClassContainer( linkableTerrain, stream );
00876 }
00877 armor = stream.readInt();
00878
00879 for ( int i = 0; i < cwettertypennum; ++i ) {
00880 fieldModification[i].terrainaccess.read( stream );
00881 fieldModification[i].terrain_and.read ( stream );
00882 fieldModification[i].terrain_or.read ( stream );
00883 fieldModification[i].movemalus_plus.read ( stream, 0 );
00884 fieldModification[i].movemalus_abs.read ( stream, -1 );
00885 }
00886
00887
00888 attackbonus_plus = stream.readInt();
00889 attackbonus_abs = stream.readInt();
00890
00891 defensebonus_plus = stream.readInt();
00892 defensebonus_abs = stream.readInt();
00893
00894 basicjamming_plus = stream.readInt();
00895 basicjamming_abs = stream.readInt();
00896
00897 if ( version >= 10 ) {
00898 viewbonus_plus = stream.readInt();
00899 viewbonus_abs = stream.readInt();
00900 }
00901
00902 if ( version <= 10 ) {
00903 imageHeight = stream.readInt();
00904 physicalHeight = imageHeight / 30;
00905 } else {
00906 imageHeight = stream.readInt();
00907 physicalHeight = stream.readInt();
00908 }
00909
00910
00911 buildcost.read( stream );
00912 removecost.read ( stream );
00913 build_movecost = stream.readInt();
00914 remove_movecost = stream.readInt();
00915
00916 canExistBeneathBuildings = stream.readInt();
00917
00918 name = stream.readString();
00919
00920 netBehaviour = stream.readInt();
00921
00922 displayMethod = stream.readInt();
00923
00924 if ( version < 15 ) {
00925 Surface s;
00926 s.read( stream );
00927 s.read( stream );
00928 }
00929
00930 techDependency.read ( stream );
00931
00932 if ( version >= 12 )
00933 growthRate = stream.readFloat();
00934 else
00935 growthRate = 0;
00936
00937 if ( version >= 13 )
00938 lifetime = stream.readInt();
00939 else
00940 lifetime = -1;
00941
00942
00943 for ( int ww = 0; ww < cwettertypennum; ww++ )
00944 if ( weather.test ( ww ) ) {
00945
00946 int pictnum = stream.readInt();
00947 stream.readInt( );
00948
00949 weatherPicture[ww].bi3pic.resize( pictnum );
00950 weatherPicture[ww].flip.resize( pictnum );
00951 weatherPicture[ww].images.resize( pictnum );
00952
00953 for ( int n = 0; n < pictnum; n++ ) {
00954 int bi3 = stream.readInt();
00955 if ( bi3 == 1 ) {
00956 weatherPicture[ww].bi3pic[n] = stream.readInt();
00957 weatherPicture[ww].flip[n] = stream.readInt();
00958 } else {
00959 weatherPicture[ww].bi3pic[n] = -1;
00960 weatherPicture[ww].images[n].read ( stream );
00961 if ( object_version >= 13 )
00962 weatherPicture[ww].flip[n] = stream.readInt();
00963 else
00964 weatherPicture[ww].flip[n] = 0;
00965 }
00966 }
00967 }
00968
00969 if ( version >= 16 )
00970 namingMethod = NamingMethod( stream.readInt() );
00971
00972 if ( version >= 17 )
00973 growthDuration = stream.readInt();
00974
00975 if ( version >= 18 )
00976 rotateImage = stream.readInt();
00977
00978 if ( version >= 19 )
00979 growOnUnits = stream.readInt();
00980
00981 if ( version >= 20 )
00982 readClassContainer( secondaryIDs, stream );
00983
00984 } else
00985 throw tinvalidversion ( stream.getLocation(), object_version, version );
00986 }
00987
00988
00989 void ObjectType :: write ( tnstream& stream ) const
00990 {
00991 stream.writeInt ( object_version );
00992
00993 stream.writeInt ( id );
00994 stream.writeInt ( groupID );
00995
00996 int ___weather = 0;
00997 for ( int i = 0; i < cwettertypennum; i++ )
00998 if ( weather.test ( i ))
00999 ___weather |= 1 << i;
01000 stream.writeInt ( ___weather );
01001 stream.writeInt ( visibleago );
01002
01003 writeClassContainer ( linkableObjects, stream );
01004 writeClassContainer ( linkableTerrain, stream );
01005
01006 stream.writeInt ( armor );
01007
01008 for ( int i = 0; i < cwettertypennum; i++ ) {
01009 fieldModification[i].terrainaccess.write( stream );
01010 fieldModification[i].terrain_and.write ( stream );
01011 fieldModification[i].terrain_or.write ( stream );
01012 fieldModification[i].movemalus_plus.write ( stream );
01013 fieldModification[i].movemalus_abs.write ( stream );
01014 }
01015
01016
01017 stream.writeInt ( attackbonus_plus );
01018 stream.writeInt ( attackbonus_abs );
01019 stream.writeInt ( defensebonus_plus );
01020 stream.writeInt ( defensebonus_abs );
01021
01022 stream.writeInt ( basicjamming_plus );
01023 stream.writeInt ( basicjamming_abs );
01024
01025 stream.writeInt ( viewbonus_plus );
01026 stream.writeInt ( viewbonus_abs );
01027
01028
01029 stream.writeInt ( imageHeight );
01030 stream.writeInt ( physicalHeight );
01031
01032 buildcost.write( stream );
01033 removecost.write ( stream );
01034 stream.writeInt( build_movecost );
01035 stream.writeInt( remove_movecost );
01036
01037 stream.writeInt( canExistBeneathBuildings );
01038
01039 stream.writeString ( name );
01040
01041 stream.writeInt ( netBehaviour );
01042
01043 stream.writeInt ( displayMethod );
01044
01045 techDependency.write ( stream );
01046
01047 stream.writeFloat( growthRate );
01048 stream.writeInt( lifetime );
01049
01050
01051 for ( int ww = 0; ww < cwettertypennum; ww++ )
01052 if ( weather.test( ww ) ) {
01053 stream.writeInt( weatherPicture[ww].images.size() );
01054 stream.writeInt( 0 );
01055
01056 for ( int l = 0; l < weatherPicture[ww].images.size(); l++ ) {
01057 if ( weatherPicture[ww].bi3pic[l] >= 0 ) {
01058 stream.writeInt ( 1 );
01059 stream.writeInt ( weatherPicture[ww].bi3pic[l] );
01060 } else {
01061 stream.writeInt ( 2 );
01062 weatherPicture[ww].images[l].write( stream );
01063 }
01064 stream.writeInt ( weatherPicture[ww].flip.at(l) );
01065 }
01066 }
01067
01068 stream.writeInt( namingMethod );
01069 stream.writeInt( growthDuration );
01070 stream.writeInt( rotateImage );
01071 stream.writeInt( growOnUnits );
01072
01073 writeClassContainer( secondaryIDs, stream );
01074
01075 }
01076
01077
01078 void ObjectType :: FieldModification :: runTextIO ( PropertyContainer& pc )
01079 {
01080 pc.addDFloatArray ( "Movemalus_plus", movemalus_plus );
01081 size_t mm = movemalus_plus.size();
01082 movemalus_plus.resize( cmovemalitypenum );
01083 for ( size_t i = mm; i < cmovemalitypenum; i++ ) {
01084 if ( i == 0 )
01085 movemalus_plus[i] = 0;
01086 else
01087 movemalus_plus[i] = movemalus_plus[0];
01088 }
01089
01090
01091 pc.addDFloatArray ( "Movemalus_abs", movemalus_abs );
01092 mm = movemalus_abs.size();
01093 movemalus_abs.resize( cmovemalitypenum );
01094 for ( size_t i = mm; i < cmovemalitypenum; i++ ) {
01095 if ( i == 0 )
01096 movemalus_abs[i] = -1;
01097 else
01098 movemalus_abs[i] = movemalus_abs[0];
01099 }
01100
01101 pc.openBracket ( "TerrainAccess" );
01102 terrainaccess.runTextIO ( pc );
01103 pc.closeBracket ();
01104
01105 pc.addTagArray ( "TerrainProperties_Filter", terrain_and, terrainPropertyNum, terrainProperties, true );
01106 pc.addTagArray ( "TerrainProperties_Add", terrain_or, terrainPropertyNum, terrainProperties );
01107 }
01108
01109 void ObjectType :: runTextIO ( PropertyContainer& pc )
01110 {
01111 pc.addBreakpoint();
01112
01113 pc.addInteger ( "ID", id );
01114
01115 if ( pc.find( "SecondaryIDs") || !pc.isReading())
01116 pc.addIntegerArray("SecondaryIDs", secondaryIDs );
01117
01118 pc.addInteger ( "GroupID", groupID, -1 );
01119 pc.addTagArray ( "Weather", weather, cwettertypennum, weatherTags );
01120 pc.addBool ( "visible_in_fogOfWar", visibleago );
01121 pc.addIntRangeArray ( "LinkableObjects", linkableObjects );
01122 if ( pc.find ( "LinkableTerrain" ) || !pc.isReading() )
01123 pc.addIntRangeArray ( "LinkableTerrain", linkableTerrain );
01124
01125 pc.addBool ( "canExistBeneathBuildings", canExistBeneathBuildings, false );
01126
01127 pc.addInteger ( "Armor", armor );
01128
01129 bool oldWeatherSpecification;
01130
01131 if ( pc.find ( "Movemalus_plus" )) {
01132 oldWeatherSpecification = true;
01133
01134 fieldModification[0].runTextIO ( pc );
01135
01136 for ( int i = 1; i < cwettertypennum; ++i )
01137 fieldModification[i] = fieldModification[0];
01138
01139 } else
01140 oldWeatherSpecification= false;
01141
01142
01143 pc.addInteger ( "AttackBonus_abs", attackbonus_abs );
01144 pc.addInteger ( "AttackBonus_plus", attackbonus_plus );
01145 pc.addInteger ( "DefenseBonus_abs", defensebonus_abs );
01146 pc.addInteger ( "DefenseBonus_plus", defensebonus_plus );
01147 pc.addInteger ( "Jamming_abs", basicjamming_abs );
01148
01149 if ( pc.find( "Jammming_plus"))
01150 pc.addInteger ( "Jammming_plus", basicjamming_plus );
01151 else
01152 pc.addInteger ( "Jamming_plus", basicjamming_plus );
01153
01154 pc.addInteger ( "Height", imageHeight );
01155 if ( pc.find ( "PhysicalHeight" ) || !pc.isReading() ) {
01156 pc.addInteger ( "PhysicalHeight", physicalHeight );
01157 } else
01158 physicalHeight = imageHeight / 30;
01159
01160 pc.addInteger ( "ViewBonus_abs", viewbonus_abs, -1 );
01161 pc.addInteger ( "ViewBonus_plus", viewbonus_plus, 0 );
01162
01163 pc.openBracket ( "ConstructionCost" );
01164 buildcost.runTextIO ( pc );
01165 pc.addInteger ( "Movement", build_movecost );
01166 pc.closeBracket ();
01167
01168 pc.openBracket ( "RemovalCost" );
01169 removecost.runTextIO ( pc );
01170 pc.addInteger ( "Movement", remove_movecost );
01171 pc.closeBracket ();
01172
01173 pc.addString( "Name", name );
01174 pc.addTagInteger ( "NamingMethod", namingMethod, namingMethodNum, namingMethodNames, int(0) );
01175
01176 pc.addDFloat( "GrowthRate", growthRate, 0 );
01177 pc.addInteger( "MaxChildSpawnNumber", growthDuration, -1 );
01178 pc.addInteger( "LifeTime", lifetime, -1 );
01179 pc.addBool( "GrowOnUnits", growOnUnits, false );
01180
01181
01182 pc.addTagInteger ( "NetBehaviour", netBehaviour, netBehaviourNum, objectNetMethod, int(NetToSelf) );
01183
01184 if ( pc.isReading() && pc.find ( "NoSelfChaining" )) {
01185 bool no_autonet;
01186 pc.addBool ( "NoSelfChaining", no_autonet );
01187 if ( !no_autonet )
01188 netBehaviour |= NetToSelf;
01189 }
01190
01191
01192 for ( int i = 0; i < cwettertypennum; i++ )
01193 if ( weather.test(i) ) {
01194
01195 pc.openBracket ( weatherTags[i] );
01196 bool bi3pics = false;
01197
01198 if ( !pc.isReading() )
01199 for ( int j = 0; j < weatherPicture[i].bi3pic.size(); j++ )
01200 if ( weatherPicture[i].bi3pic[j] >= 0 )
01201 bi3pics = true;
01202
01203 pc.addBool ( "UseGFXpics", bi3pics );
01204 if ( bi3pics ) {
01205 pc.addIntegerArray ( "GFXpictures", weatherPicture[i].bi3pic );
01206 pc.addIntegerArray ( "FlipPictures", weatherPicture[i].flip );
01207
01208 weatherPicture[i].flip.resize( weatherPicture[i].bi3pic.size() );
01209 weatherPicture[i].images.resize( weatherPicture[i].bi3pic.size() );
01210 } else {
01211 ASCString s = extractFileName_withoutSuffix( filename );
01212 if ( s.empty() ) {
01213 s = "object";
01214 s += strrr(id);
01215 }
01216 pc.addImageArray ( "picture", weatherPicture[i].images, s + weatherAbbrev[i] );
01217 weatherPicture[i].bi3pic.resize( weatherPicture[i].images.size() );
01218 weatherPicture[i].flip.resize( weatherPicture[i].images.size() );
01219
01220 if ( pc.find ( "FlipPictures" ) ) {
01221 vector<int> imgReferences;
01222 imgReferences.resize ( weatherPicture[i].images.size() );
01223
01224 for ( int j = 0; j < weatherPicture[i].images.size(); j++ ) {
01225 weatherPicture[i].bi3pic[j] = -1;
01226 weatherPicture[i].flip[j] = 0;
01227 imgReferences[j] = -1;
01228 }
01229
01230 pc.addIntegerArray ( "FlipPictures", weatherPicture[i].flip );
01231 pc.addIntegerArray ( "ImageReference", imgReferences );
01232
01233 for ( int j = 0; j < weatherPicture[i].images.size(); j++ )
01234 if ( j < imgReferences.size() && imgReferences[j] >= 0 && imgReferences[j] < weatherPicture[i].images.size() )
01235 weatherPicture[i].images[j] = weatherPicture[i].images[imgReferences[j]];
01236
01237 while ( weatherPicture[i].flip.size() < weatherPicture[i].images.size() )
01238 weatherPicture[i].flip.push_back(0);
01239
01240 } else {
01241 for ( int u = 0; u < weatherPicture[i].images.size(); u++ ) {
01242 weatherPicture[i].bi3pic[u] = -1;
01243 weatherPicture[i].flip[u] = 0;
01244 }
01245 }
01246
01247 if ( pc.isReading() ) {
01248 int operations;
01249 std::set<void*> processedImages;
01250 pc.addNamedInteger("GraphicOperations", operations, graphicOperationNum, graphicOperations, 0 );
01251 if ( operations == 1 ) {
01252 for ( int j = 0; j < weatherPicture[i].images.size(); j++ )
01253 if ( processedImages.find( weatherPicture[i].images[j].getBaseSurface() ) == processedImages.end() ) {
01254 snowify( weatherPicture[i].images[j] );
01255 processedImages.insert( weatherPicture[i].images[j].getBaseSurface() ) ;
01256 }
01257 } else
01258 if ( operations == 2 ) {
01259 for ( int j = 0; j < weatherPicture[i].images.size(); j++ )
01260 if ( processedImages.find( weatherPicture[i].images[j].getBaseSurface() ) == processedImages.end() ) {
01261 snowify( weatherPicture[i].images[j], false );
01262 processedImages.insert( weatherPicture[i].images[j].getBaseSurface() ) ;
01263 }
01264
01265 }
01266 }
01267
01268 }
01269
01270 if ( pc.find ( "DisplayMethod" ) ) {
01271 pc.addNamedInteger( "DisplayMethod", displayMethod, objectDisplayingMethodNum, objectDisplayingMethodTags );
01272 if ( displayMethod == 2 && pc.isReading() && weatherPicture[i].images[0].GetPixelFormat().BitsPerPixel() != 8 )
01273 pc.error("Error parsing object " + name + " (ID=" + ASCString::toString(id)+"): invalid image; displaymethod=translation is only a available for 8 Bit images");
01274
01275 } else
01276 displayMethod = 0;
01277
01278
01279 if ( !oldWeatherSpecification ) {
01280 fieldModification[i].runTextIO( pc );
01281 }
01282 pc.closeBracket ( );
01283 }
01284
01285 techDependency.runTextIO( pc );
01286
01287 if ( weatherPicture[0].images.size() == 1 && (netBehaviour&KeepOrientation) )
01288 rotateImage = true;
01289
01290
01291
01292 }