2626#include < boost/range/adaptor/indexed.hpp>
2727#include < iostream>
2828
29+ namespace {
30+ constexpr uint16_t COLOR_BLOCK_HEADER = 0x01F5 ;
31+ constexpr uint16_t IMAGE_DATA_HEADER = 0x01F4 ;
32+ // / 8 Animation Steps, 6 directions, 2 types (Fat, Non-Fat) --> Array [fat][direction][animStep]
33+ constexpr unsigned NUM_BODY_IMAGES = 2 * 6 * 8 ;
34+ // / Same for links but Array [animStep][fat][direction]
35+ constexpr unsigned NUM_LINKS_PER_OVERLAY = 8 * 2 * 6 ;
36+ constexpr uint16_t SPRITE_WIDTH = 32 ;
37+ // / Draw offset in X
38+ constexpr uint16_t X_OFFSET = 16 ;
39+ } // namespace
40+
2941namespace libsiedler2 {
3042// / Read a block of colors used later
3143static int readColorBlock (libendian::EndianIStreamAdapter<false , std::istream&>& fs, std::vector<uint8_t >& pixels)
@@ -34,7 +46,7 @@ static int readColorBlock(libendian::EndianIStreamAdapter<false, std::istream&>&
3446 if (!(fs >> id >> size))
3547 return ErrorCode::UNEXPECTED_EOF;
3648
37- if (id != 0x01F5 )
49+ if (id != COLOR_BLOCK_HEADER )
3850 return ErrorCode::WRONG_FORMAT;
3951
4052 pixels.resize (size);
@@ -50,7 +62,7 @@ static int readImageData(libendian::EndianIStreamAdapter<false, std::istream&>&
5062 if (!(fs >> id >> height))
5163 return ErrorCode::UNEXPECTED_EOF;
5264
53- if (id != 0x01F4 )
65+ if (id != IMAGE_DATA_HEADER )
5466 return ErrorCode::WRONG_FORMAT;
5567
5668 starts.resize (height);
@@ -59,12 +71,7 @@ static int readImageData(libendian::EndianIStreamAdapter<false, std::istream&>&
5971 return ErrorCode::NONE;
6072}
6173
62- /* * @class ArchivItem_Bob
63- *
64- * Klasse für Bobfiles.
65- */
66-
67- ArchivItem_Bob::ArchivItem_Bob () : ArchivItem(BobType::Bob), numGoodImgs(0 ) {}
74+ ArchivItem_Bob::ArchivItem_Bob () : ArchivItem(BobType::Bob), numOverlayImgs(0 ) {}
6875
6976ArchivItem_Bob::~ArchivItem_Bob () = default ;
7077
@@ -90,9 +97,10 @@ int ArchivItem_Bob::load(std::istream& file, const ArchivItem_Palette* palette)
9097 if (int ec = readColorBlock (fs, raw_base))
9198 return ec;
9299
93- // Einzelner Bilder auslesen ( untere Körper ): 8 Animation Steps, 6 directions, 2 types (Fat, Non-Fat) = 96
94- alloc (96 );
95- for (uint32_t i = 0 ; i < 96 ; ++i)
100+ // Read body images (to get full figure draw this then draw the item image (below) over it)
101+ // They form an array [fat][direction][animStep]
102+ alloc (NUM_BODY_IMAGES);
103+ for (uint32_t i = 0 ; i < NUM_BODY_IMAGES; ++i)
96104 {
97105 std::vector<uint16_t > starts;
98106 uint8_t ny;
@@ -101,17 +109,17 @@ int ArchivItem_Bob::load(std::istream& file, const ArchivItem_Palette* palette)
101109
102110 auto image = getAllocator ().create <ArchivItem_Bitmap_Player>(BobType::BitmapPlayer);
103111 assert (image);
104- image->setNx (16 ); // -V522
112+ image->setNx (X_OFFSET);
105113 image->setNy (ny);
106114
107- int ec = image->load (32 , raw_base, starts, true , palette);
115+ int ec = image->load (SPRITE_WIDTH , raw_base, starts, true , palette);
108116 if (ec)
109117 return ec;
110118
111119 set (i, std::move (image));
112120 }
113121
114- // erstmal die 6 Farbblöcke fr die 6 Richtungen
122+ // Color blocks for each direction
115123 std::array<std::vector<uint8_t >, 6 > raw;
116124
117125 for (auto & i : raw)
@@ -120,55 +128,58 @@ int ArchivItem_Bob::load(std::istream& file, const ArchivItem_Palette* palette)
120128 return ec;
121129 }
122130
123- // Anzahl Warenbilder
124- fs >> numGoodImgs ;
131+ // Number of overlay images (e.g. goods of carriers)
132+ fs >> numOverlayImgs ;
125133
126- alloc_inc (numGoodImgs );
134+ alloc_inc (numOverlayImgs );
127135
128- std::vector<std::vector<uint16_t >> starts (numGoodImgs );
129- std::vector<uint8_t > ny (numGoodImgs );
136+ std::vector<std::vector<uint16_t >> starts (numOverlayImgs );
137+ std::vector<uint8_t > ny (numOverlayImgs );
130138
131- for (uint16_t i = 0 ; i < numGoodImgs ; ++i)
139+ for (uint16_t i = 0 ; i < numOverlayImgs ; ++i)
132140 {
133141 if (int ec = readImageData (fs, starts[i], ny[i]))
134142 return ec;
135143 }
136144
137145 // Number of complete pictures.
138- // Links form an array: [ware ][animStep][fat][direction]: [][8][2][6]
139- // the item at position 96 + link[ware ][animStep][fat][direction] shall be combined
146+ // Links form an array: [overlay ][animStep][fat][direction]: [][8][2][6]
147+ // the item at position NUM_BODY_IMAGES + link[overlay ][animStep][fat][direction] shall be combined
140148 // with the appropriate body
141- uint16_t item_count ;
142- if (!(fs >> item_count ))
149+ uint16_t numLinks ;
150+ if (!(fs >> numLinks ))
143151 return ErrorCode::UNEXPECTED_EOF;
144152
145- links.resize (item_count );
146- std::vector<bool > loaded (numGoodImgs , false );
153+ links.resize (numLinks );
154+ std::vector<bool > loaded (numOverlayImgs , false );
147155
148- for (uint32_t i = 0 ; i < item_count ; ++i)
156+ for (uint32_t i = 0 ; i < numLinks ; ++i)
149157 {
150158 uint16_t unknown;
151159 if (!(fs >> links[i] >> unknown))
152160 return ErrorCode::UNEXPECTED_EOF;
153161
154- if (links[i] >= numGoodImgs )
162+ if (links[i] >= numOverlayImgs )
155163 return ErrorCode::WRONG_FORMAT;
156164
157165 if (loaded[links[i]])
158166 continue ;
159167
160168 auto image = getAllocator ().create <ArchivItem_Bitmap_Player>(BobType::BitmapPlayer);
161169 assert (image);
162- image->setNx (16 ); // -V522
170+ image->setNx (X_OFFSET);
163171 image->setNy (ny[links[i]]);
164172
165- int ec = image->load (32 , raw[i % 6 ], starts[links[i]], true , palette);
173+ int ec = image->load (SPRITE_WIDTH , raw[i % 6 ], starts[links[i]], true , palette);
166174 if (ec)
167175 return ec;
168176
169- set (96 + links[i], std::move (image));
177+ set (NUM_BODY_IMAGES + links[i], std::move (image));
170178 loaded[links[i]] = true ;
171179 }
180+ // Adjust links so they point to actual indices in the archive as we moved them by NUM_BODY_IMAGES
181+ for (auto & link : links)
182+ link += NUM_BODY_IMAGES;
172183
173184 return (!fs) ? ErrorCode::UNEXPECTED_EOF : ErrorCode::NONE;
174185}
@@ -186,21 +197,37 @@ int ArchivItem_Bob::write(std::ostream&, const ArchivItem_Palette*)
186197 return ErrorCode::UNSUPPORTED_FORMAT;
187198}
188199
200+ ArchivItem_Bitmap_Player* ArchivItem_Bob::getBody (bool fat, ImgDir direction, unsigned animationstep)
201+ {
202+ // Array: [fat][direction][animStep]: [2][6][8]
203+ const unsigned bodyIdx = (fat * 6 + static_cast <unsigned >(direction)) * 8 + animationstep;
204+ return dynamic_cast <ArchivItem_Bitmap_Player*>(get (bodyIdx));
205+ }
206+
207+ ArchivItem_Bitmap_Player* ArchivItem_Bob::getOverlay (unsigned overlayIdx, bool fat, ImgDir direction, unsigned animationstep)
208+ {
209+ return dynamic_cast <ArchivItem_Bitmap_Player*>(get (getOverlayIdx (overlayIdx, fat, direction, animationstep)));
210+ }
211+
189212void ArchivItem_Bob::writeLinks (std::ostream& file) const
190213{
191214 // links[][8][2][6]
192215 for (const auto it : links | boost::adaptors::indexed ())
193216 {
194- if (it.index () % ( 8 * 2 * 6 ) == 0 )
195- file << " # Job ID " << it.index () / ( 8 * 2 * 6 ) << " \n " ;
217+ if (it.index () % NUM_LINKS_PER_OVERLAY == 0 )
218+ file << " # Job ID " << it.index () / NUM_LINKS_PER_OVERLAY << " \n " ;
196219 file << s25util::toStringClassic (it.index ()) << " \t " << s25util::toStringClassic (it.value ()) << " \n " ;
197220 }
198221}
199222
200- std::map<unsigned , uint16_t > ArchivItem_Bob::readLinks (std::istream& file)
223+ std::map<uint16_t , uint16_t > ArchivItem_Bob::readLinks (std::istream& file)
201224{
202- std::map<unsigned , uint16_t > result;
203- loadMapping (file, [&result](unsigned idx, const std::string& value) { result[idx] = s25util::fromStringClassic<uint16_t >(value); });
225+ std::map<uint16_t , uint16_t > result;
226+ loadMapping (file, [&result](unsigned idx, const std::string& value) {
227+ if (idx > std::numeric_limits<uint16_t >::max ())
228+ throw std::range_error (" Index " + std::to_string (idx) + " is to large" );
229+ result[idx] = s25util::fromStringClassic<uint16_t >(value);
230+ });
204231 return result;
205232}
206233
0 commit comments