1 /*************************************************************************** 2 * Free Heroes of Might and Magic II: https://github.com/ihhub/fheroes2 * 3 * Copyright (C) 2021 * 4 * * 5 * This program is free software; you can redistribute it and/or modify * 6 * it under the terms of the GNU General Public License as published by * 7 * the Free Software Foundation; either version 2 of the License, or * 8 * (at your option) any later version. * 9 * * 10 * This program is distributed in the hope that it will be useful, * 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 * GNU General Public License for more details. * 14 * * 15 * You should have received a copy of the GNU General Public License * 16 * along with this program; if not, write to the * 17 * Free Software Foundation, Inc., * 18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 19 ***************************************************************************/ 20 21 #include <array> 22 #include <cassert> 23 #include <cstring> 24 #include <map> 25 #include <vector> 26 27 #include "agg.h" 28 #include "agg_file.h" 29 #include "agg_image.h" 30 #include "h2d.h" 31 #include "icn.h" 32 #include "image.h" 33 #include "image_tool.h" 34 #include "pal.h" 35 #include "screen.h" 36 #include "text.h" 37 #include "til.h" 38 #include "ui_language.h" 39 #include "ui_text.h" 40 41 namespace 42 { 43 const std::array<const char *, TIL::LASTTIL> tilFileName = { "UNKNOWN", "CLOF32.TIL", "GROUND32.TIL", "STON.TIL" }; 44 45 std::vector<std::vector<fheroes2::Sprite>> _icnVsSprite( ICN::LASTICN ); 46 std::vector<std::vector<std::vector<fheroes2::Image>>> _tilVsImage( TIL::LASTTIL ); 47 const fheroes2::Sprite errorImage; 48 49 const uint32_t headerSize = 6; 50 51 std::map<int, std::vector<fheroes2::Sprite>> _icnVsScaledSprite; 52 IsValidICNId(int id)53 bool IsValidICNId( int id ) 54 { 55 return id >= 0 && static_cast<size_t>( id ) < _icnVsSprite.size(); 56 } 57 IsValidTILId(int id)58 bool IsValidTILId( int id ) 59 { 60 return id >= 0 && static_cast<size_t>( id ) < _tilVsImage.size(); 61 } 62 createDigit(const int32_t width,const int32_t height,const std::vector<fheroes2::Point> & points)63 fheroes2::Image createDigit( const int32_t width, const int32_t height, const std::vector<fheroes2::Point> & points ) 64 { 65 fheroes2::Image digit( width, height ); 66 digit.reset(); 67 68 fheroes2::SetPixel( digit, points, 115 ); 69 fheroes2::Blit( fheroes2::CreateContour( digit, 35 ), digit ); 70 71 return digit; 72 } 73 addDigit(const fheroes2::Sprite & original,const fheroes2::Image & digit,const fheroes2::Point & offset)74 fheroes2::Image addDigit( const fheroes2::Sprite & original, const fheroes2::Image & digit, const fheroes2::Point & offset ) 75 { 76 fheroes2::Image combined( original.width() + digit.width() + offset.x, original.height() + ( offset.y < 0 ? 0 : offset.y ) ); 77 combined.reset(); 78 79 fheroes2::Copy( original, 0, 0, combined, 0, 0, original.width(), original.height() ); 80 fheroes2::Blit( digit, 0, 0, combined, original.width() + offset.x, combined.height() - digit.height() + ( offset.y >= 0 ? 0 : offset.y ), digit.width(), 81 digit.height() ); 82 83 return combined; 84 } 85 populateCursorIcons(std::vector<fheroes2::Sprite> & output,const fheroes2::Sprite & origin,const std::vector<fheroes2::Image> & digits,const fheroes2::Point & offset)86 void populateCursorIcons( std::vector<fheroes2::Sprite> & output, const fheroes2::Sprite & origin, const std::vector<fheroes2::Image> & digits, 87 const fheroes2::Point & offset ) 88 { 89 output.emplace_back( origin ); 90 for ( size_t i = 0; i < digits.size(); ++i ) { 91 output.emplace_back( addDigit( origin, digits[i], offset ) ); 92 output.back().setPosition( output.back().width() - origin.width(), output.back().height() - origin.height() ); 93 } 94 } 95 replaceTranformPixel(fheroes2::Image & image,const int32_t position,const uint8_t value)96 void replaceTranformPixel( fheroes2::Image & image, const int32_t position, const uint8_t value ) 97 { 98 if ( image.transform()[position] != 0 ) { 99 image.transform()[position] = 0; 100 image.image()[position] = value; 101 } 102 } 103 104 // This class serves the purpose of preserving the original alphabet which is loaded from AGG files for cases when we generate new language alphabet. 105 class OriginalAlphabetPreserver 106 { 107 public: preserve()108 void preserve() 109 { 110 if ( _isPreserved ) { 111 return; 112 } 113 114 fheroes2::AGG::GetICN( ICN::FONT, 0 ); 115 fheroes2::AGG::GetICN( ICN::SMALFONT, 0 ); 116 117 _normalFont = _icnVsSprite[ICN::FONT]; 118 _smallFont = _icnVsSprite[ICN::SMALFONT]; 119 120 _isPreserved = true; 121 } 122 restore() const123 void restore() const 124 { 125 if ( !_isPreserved ) { 126 return; 127 } 128 129 // Restore the original font. 130 _icnVsSprite[ICN::FONT] = _normalFont; 131 _icnVsSprite[ICN::SMALFONT] = _smallFont; 132 133 // Clear modified fonts. 134 _icnVsSprite[ICN::YELLOW_FONT].clear(); 135 _icnVsSprite[ICN::YELLOW_SMALLFONT].clear(); 136 _icnVsSprite[ICN::GRAY_FONT].clear(); 137 _icnVsSprite[ICN::GRAY_SMALL_FONT].clear(); 138 _icnVsSprite[ICN::WHITE_LARGE_FONT].clear(); 139 } 140 141 private: 142 bool _isPreserved = false; 143 144 std::vector<fheroes2::Sprite> _normalFont; 145 std::vector<fheroes2::Sprite> _smallFont; 146 }; 147 148 OriginalAlphabetPreserver alphabetPreserver; 149 generatePolishAlphabet()150 void generatePolishAlphabet() 151 { 152 for ( const int icnId : { ICN::FONT, ICN::SMALFONT } ) { 153 std::vector<fheroes2::Sprite> & original = _icnVsSprite[icnId]; 154 155 original.resize( 96 ); 156 original.insert( original.end(), 128, original[0] ); 157 original[108] = original[51]; 158 original[111] = original[58]; 159 original[124] = original[83]; 160 original[127] = original[90]; 161 original[131] = original[44]; 162 original[133] = original[33]; 163 original[143] = original[58]; 164 original[147] = original[76]; 165 original[153] = original[65]; 166 original[159] = original[90]; 167 original[166] = original[35]; 168 original[170] = original[37]; 169 original[177] = original[46]; 170 original[179] = original[47]; 171 original[198] = original[67]; 172 original[202] = original[69]; 173 original[209] = original[78]; 174 original[211] = original[79]; 175 } 176 177 // TODO: modify newly added characters accordingly. 178 } 179 generateGermanAlphabet()180 void generateGermanAlphabet() 181 { 182 for ( const int icnId : { ICN::FONT, ICN::SMALFONT } ) { 183 std::vector<fheroes2::Sprite> & original = _icnVsSprite[icnId]; 184 185 original.resize( 103 ); 186 original[96] = original[65]; 187 original[97] = original[79]; 188 original[98] = original[85]; 189 original[99] = original[34]; 190 original[100] = original[33]; 191 original[101] = original[47]; 192 original[102] = original[53]; 193 } 194 195 // TODO: modify newly added characters accordingly. 196 } 197 generateFrenchAlphabet()198 void generateFrenchAlphabet() 199 { 200 // Resize fonts. 201 for ( const int icnId : { ICN::FONT, ICN::SMALFONT } ) { 202 _icnVsSprite[icnId].resize( 96 ); 203 } 204 205 // Normal font. 206 { 207 std::vector<fheroes2::Sprite> & font = _icnVsSprite[ICN::FONT]; 208 209 font[3].resize( font[79].width(), font[79].height() + 3 ); 210 font[3].reset(); 211 fheroes2::Copy( font[79], 0, 0, font[3], 0, 3, font[79].width(), font[79].height() ); 212 // generate ^ on the top. 213 fheroes2::Copy( font[3], 2, 3, font[3], 3, 0, 1, 1 ); 214 fheroes2::Copy( font[3], 4, 3, font[3], 4, 0, 1, 1 ); 215 fheroes2::Copy( font[3], 2, 3, font[3], 5, 0, 1, 1 ); 216 fheroes2::Copy( font[3], 2, 3, font[3], 2, 1, 1, 1 ); 217 fheroes2::Copy( font[3], 4, 3, font[3], 3, 1, 1, 1 ); 218 fheroes2::Copy( font[3], 4, 3, font[3], 5, 1, 1, 1 ); 219 fheroes2::Copy( font[3], 2, 3, font[3], 6, 1, 1, 1 ); 220 font[3].setPosition( font[79].x(), font[79].y() - 3 ); 221 fheroes2::updateShadow( font[3], { -1, 2 }, 2 ); 222 223 font[4].resize( font[85].width(), font[85].height() + 3 ); 224 font[4].reset(); 225 fheroes2::Copy( font[85], 0, 0, font[4], 0, 3, font[85].width(), font[85].height() ); 226 fheroes2::Copy( font[3], 2, 0, font[4], 3, 0, 5, 2 ); 227 font[4].setPosition( font[85].x(), font[85].y() - 3 ); 228 fheroes2::updateShadow( font[4], { -1, 2 }, 2 ); 229 230 font[6].resize( font[85].width(), font[85].height() + 3 ); 231 font[6].reset(); 232 // generate -_ on the top. 233 fheroes2::Copy( font[85], 0, 0, font[6], 0, 3, font[85].width(), font[85].height() ); 234 fheroes2::Copy( font[6], 2, 3, font[6], 4, 0, 1, 1 ); 235 fheroes2::Copy( font[6], 2, 4, font[6], 5, 0, 1, 1 ); 236 fheroes2::Copy( font[6], 2, 3, font[6], 5, 1, 1, 1 ); 237 fheroes2::Copy( font[6], 2, 4, font[6], 6, 1, 1, 1 ); 238 fheroes2::Copy( font[6], 3, 3, font[6], 7, 1, 1, 1 ); 239 font[6].setPosition( font[85].x(), font[85].y() - 3 ); 240 fheroes2::updateShadow( font[6], { -1, 2 }, 2 ); 241 242 font[10].resize( font[65].width(), font[65].height() + 3 ); 243 font[10].reset(); 244 fheroes2::Copy( font[65], 0, 0, font[10], 0, 3, font[65].width(), font[65].height() ); 245 fheroes2::Copy( font[3], 2, 0, font[10], 2, 0, 5, 2 ); 246 font[10].setPosition( font[65].x(), font[65].y() - 3 ); 247 fheroes2::updateShadow( font[10], { -1, 2 }, 2 ); 248 249 font[28] = font[73]; 250 font[28].image()[2] = 0; 251 font[28].transform()[2] = 1; 252 font[28].image()[2 + font[28].width()] = 0; 253 font[28].transform()[2 + font[28].width()] = 1; 254 fheroes2::Copy( font[28], 3, 0, font[28], 1, 0, 1, 2 ); 255 fheroes2::updateShadow( font[28], { -1, 2 }, 2 ); 256 257 font[30] = font[73]; 258 font[30].image()[1] = 0; 259 font[30].transform()[1] = 1; 260 font[30].image()[3] = 0; 261 font[30].transform()[3] = 1; 262 font[30].image()[2 + font[30].width()] = 0; 263 font[30].transform()[2 + font[30].width()] = 1; 264 fheroes2::Copy( font[30], 2, 0, font[30], 1, 1, 1, 1 ); 265 fheroes2::Copy( font[30], 2, 0, font[30], 3, 1, 1, 1 ); 266 fheroes2::updateShadow( font[30], { -1, 2 }, 2 ); 267 268 font[32].resize( font[65].width(), font[65].height() + 3 ); 269 font[32].reset(); 270 fheroes2::Copy( font[65], 0, 0, font[32], 0, 3, font[65].width(), font[65].height() ); 271 font[32].setPosition( font[65].x(), font[65].y() - 3 ); 272 fheroes2::Copy( font[6], 4, 0, font[32], 3, 0, 4, 2 ); 273 fheroes2::updateShadow( font[32], { -1, 2 }, 2 ); 274 275 font[62].resize( font[67].width(), font[67].height() + 2 ); 276 font[62].reset(); 277 fheroes2::Copy( font[67], 0, 0, font[62], 0, 0, font[67].width(), font[67].height() ); 278 fheroes2::Copy( font[67], 2, 1, font[62], 4, 7, 1, 1 ); 279 fheroes2::Copy( font[67], 5, 6, font[62], 5, 7, 1, 1 ); 280 fheroes2::Copy( font[67], 2, 6, font[62], 6, 7, 1, 1 ); 281 fheroes2::Copy( font[67], 2, 1, font[62], 5, 8, 1, 1 ); 282 fheroes2::Copy( font[67], 5, 6, font[62], 6, 8, 1, 1 ); 283 fheroes2::Copy( font[67], 2, 1, font[62], 4, 9, 1, 1 ); 284 fheroes2::Copy( font[67], 5, 6, font[62], 5, 9, 1, 1 ); 285 fheroes2::Copy( font[67], 3, 0, font[62], 6, 9, 1, 1 ); 286 font[62].setPosition( font[67].x(), font[67].y() ); 287 fheroes2::updateShadow( font[62], { -1, 2 }, 2 ); 288 289 font[64].resize( font[69].width(), font[69].height() + 3 ); 290 font[64].reset(); 291 fheroes2::Copy( font[69], 0, 0, font[64], 0, 3, font[69].width(), font[69].height() ); 292 fheroes2::Copy( font[64], 4, 3, font[64], 4, 0, 1, 1 ); 293 fheroes2::Copy( font[64], 4, 3, font[64], 5, 1, 1, 1 ); 294 fheroes2::Copy( font[64], 8, 6, font[64], 5, 0, 1, 1 ); 295 fheroes2::Copy( font[64], 8, 6, font[64], 6, 1, 1, 1 ); 296 fheroes2::Copy( font[64], 4, 8, font[64], 6, 2, 1, 1 ); 297 font[64].setPosition( font[69].x(), font[69].y() - 3 ); 298 fheroes2::updateShadow( font[64], { -1, 2 }, 2 ); 299 300 font[91] = font[28]; 301 302 font[92].resize( font[69].width(), font[69].height() + 3 ); 303 font[92].reset(); 304 fheroes2::Copy( font[69], 0, 0, font[92], 0, 3, font[69].width(), font[69].height() ); 305 fheroes2::Copy( font[3], 2, 0, font[92], 3, 0, 5, 2 ); 306 font[92].setPosition( font[69].x(), font[69].y() - 3 ); 307 fheroes2::updateShadow( font[92], { -1, 2 }, 2 ); 308 309 font[93] = font[30]; 310 311 font[94].resize( font[69].width(), font[69].height() + 3 ); 312 font[94].reset(); 313 fheroes2::Copy( font[69], 0, 0, font[94], 0, 3, font[69].width(), font[69].height() ); 314 fheroes2::Copy( font[94], 4, 8, font[94], 3, 1, 1, 1 ); 315 fheroes2::Copy( font[94], 8, 6, font[94], 4, 1, 1, 1 ); 316 fheroes2::Copy( font[94], 8, 6, font[94], 5, 0, 1, 1 ); 317 fheroes2::Copy( font[94], 4, 3, font[94], 6, 0, 1, 1 ); 318 fheroes2::Copy( font[94], 4, 3, font[94], 5, 1, 1, 1 ); 319 font[94].setPosition( font[69].x(), font[69].y() - 3 ); 320 fheroes2::updateShadow( font[94], { -1, 2 }, 2 ); 321 322 font[95] = font[30]; 323 } 324 325 // Small font. 326 { 327 std::vector<fheroes2::Sprite> & font = _icnVsSprite[ICN::SMALFONT]; 328 329 font[3].resize( font[79].width(), font[79].height() + 2 ); 330 font[3].reset(); 331 fheroes2::Copy( font[79], 0, 0, font[3], 0, 2, font[79].width(), font[79].height() ); 332 font[3].setPosition( font[79].x(), font[79].y() - 2 ); 333 fheroes2::Copy( font[3], 2, 2, font[3], 2, 0, 1, 1 ); 334 fheroes2::Copy( font[3], 2, 2, font[3], 4, 0, 1, 1 ); 335 fheroes2::updateShadow( font[3], { -1, 1 }, 2 ); 336 337 font[4].resize( font[85].width(), font[85].height() + 2 ); 338 font[4].reset(); 339 fheroes2::Copy( font[85], 0, 0, font[4], 0, 2, font[85].width(), font[85].height() ); 340 font[4].setPosition( font[85].x(), font[85].y() - 2 ); 341 fheroes2::Copy( font[4], 1, 2, font[4], 3, 0, 1, 1 ); 342 fheroes2::Copy( font[4], 1, 2, font[4], 5, 0, 1, 1 ); 343 fheroes2::updateShadow( font[4], { -1, 1 }, 2 ); 344 345 font[6].resize( font[85].width(), font[85].height() + 2 ); 346 font[6].reset(); 347 fheroes2::Copy( font[85], 0, 0, font[6], 0, 2, font[85].width(), font[85].height() ); 348 font[6].setPosition( font[85].x(), font[85].y() - 2 ); 349 fheroes2::Copy( font[6], 1, 2, font[6], 4, 0, 1, 1 ); 350 fheroes2::updateShadow( font[6], { -1, 1 }, 2 ); 351 352 font[10].resize( font[65].width(), font[65].height() + 2 ); 353 font[10].reset(); 354 fheroes2::Copy( font[65], 0, 0, font[10], 0, 2, font[65].width(), font[65].height() ); 355 font[10].setPosition( font[65].x(), font[65].y() - 2 ); 356 fheroes2::Copy( font[10], 2, 2, font[10], 2, 1, 1, 1 ); 357 fheroes2::Copy( font[10], 2, 2, font[10], 4, 1, 1, 1 ); 358 fheroes2::Copy( font[10], 2, 2, font[10], 3, 0, 1, 1 ); 359 fheroes2::updateShadow( font[10], { -1, 1 }, 2 ); 360 361 font[28] = font[73]; 362 fheroes2::FillTransform( font[28], 0, 0, font[28].width(), 2, 1 ); 363 fheroes2::Copy( font[28], 1, 2, font[28], 1, 0, 1, 1 ); 364 fheroes2::Copy( font[28], 1, 2, font[28], 3, 0, 1, 1 ); 365 fheroes2::updateShadow( font[28], { -1, 1 }, 2 ); 366 367 font[30] = font[28]; 368 369 font[32].resize( font[65].width(), font[65].height() + 2 ); 370 font[32].reset(); 371 fheroes2::Copy( font[65], 0, 0, font[32], 0, 2, font[65].width(), font[65].height() ); 372 font[32].setPosition( font[65].x(), font[65].y() - 2 ); 373 fheroes2::Copy( font[32], 2, 2, font[32], 3, 0, 1, 1 ); 374 fheroes2::Copy( font[32], 2, 2, font[32], 4, 1, 1, 1 ); 375 fheroes2::updateShadow( font[32], { -1, 1 }, 2 ); 376 377 font[62].resize( font[67].width(), font[67].height() + 2 ); 378 font[62].reset(); 379 fheroes2::Copy( font[67], 0, 0, font[62], 0, 0, font[67].width(), font[67].height() ); 380 fheroes2::Copy( font[62], 3, 4, font[62], 3, 5, 1, 1 ); 381 fheroes2::Copy( font[62], 3, 4, font[62], 2, 6, 1, 1 ); 382 fheroes2::updateShadow( font[62], { -1, 1 }, 2 ); 383 384 font[64].resize( font[69].width(), font[69].height() + 2 ); 385 font[64].reset(); 386 fheroes2::Copy( font[69], 0, 0, font[64], 0, 2, font[69].width(), font[69].height() ); 387 font[64].setPosition( font[69].x(), font[69].y() - 2 ); 388 fheroes2::Copy( font[64], 2, 2, font[64], 2, 0, 1, 1 ); 389 fheroes2::Copy( font[64], 2, 2, font[64], 3, 1, 1, 1 ); 390 fheroes2::updateShadow( font[64], { -1, 1 }, 2 ); 391 392 font[91] = font[28]; 393 394 font[92].resize( font[69].width(), font[69].height() + 2 ); 395 font[92].reset(); 396 fheroes2::Copy( font[69], 0, 0, font[92], 0, 2, font[69].width(), font[69].height() ); 397 font[92].setPosition( font[69].x(), font[69].y() - 2 ); 398 fheroes2::Copy( font[92], 2, 2, font[92], 3, 0, 1, 1 ); 399 fheroes2::Copy( font[92], 2, 2, font[92], 2, 1, 1, 1 ); 400 fheroes2::Copy( font[92], 2, 2, font[92], 4, 1, 1, 1 ); 401 fheroes2::updateShadow( font[92], { -1, 1 }, 2 ); 402 403 font[93] = font[28]; 404 405 font[94].resize( font[69].width(), font[69].height() + 2 ); 406 font[94].reset(); 407 fheroes2::Copy( font[69], 0, 0, font[94], 0, 2, font[69].width(), font[69].height() ); 408 font[94].setPosition( font[69].x(), font[69].y() - 2 ); 409 fheroes2::Copy( font[94], 2, 2, font[94], 4, 0, 1, 1 ); 410 fheroes2::Copy( font[94], 2, 2, font[94], 3, 1, 1, 1 ); 411 fheroes2::updateShadow( font[94], { -1, 1 }, 2 ); 412 413 font[95] = font[28]; 414 } 415 } 416 generateRussianAlphabet()417 void generateRussianAlphabet() 418 { 419 // Resize fonts. 420 for ( const int icnId : { ICN::FONT, ICN::SMALFONT } ) { 421 std::vector<fheroes2::Sprite> & original = _icnVsSprite[icnId]; 422 423 original.resize( 96 ); 424 original.insert( original.end(), 128, original[0] ); 425 } 426 427 // Normal font. 428 { 429 std::vector<fheroes2::Sprite> & font = _icnVsSprite[ICN::FONT]; 430 431 size_t offset = 0; 432 433 // E with 2 dots on top. 434 font[168 - 32].resize( font[37 + offset].width(), font[37 + offset].height() + 3 ); 435 font[168 - 32].reset(); 436 fheroes2::Copy( font[37 + offset], 0, 0, font[168 - 32], 0, 3, font[37 + offset].width(), font[37 + offset].height() ); 437 fheroes2::Copy( font[168 - 32], 5, 5, font[168 - 32], 4, 0, 1, 1 ); 438 fheroes2::Copy( font[168 - 32], 5, 5, font[168 - 32], 7, 0, 1, 1 ); 439 fheroes2::Copy( font[168 - 32], 4, 5, font[168 - 32], 4, 1, 1, 1 ); 440 fheroes2::Copy( font[168 - 32], 4, 5, font[168 - 32], 7, 1, 1, 1 ); 441 font[168 - 32].setPosition( font[37 + offset].x(), font[37 + offset].y() - 3 ); 442 fheroes2::updateShadow( font[168 - 32], { -1, 2 }, 2 ); 443 444 font[192 - 32] = font[33]; 445 446 font[193 - 32] = font[34 + offset]; 447 fheroes2::FillTransform( font[193 - 32], 9, 4, 2, 1, 1 ); 448 fheroes2::Copy( font[38], 6, 0, font[193 - 32], 6, 0, 5, 4 ); 449 fheroes2::Copy( font[193 - 32], 9, 5, font[193 - 32], 8, 4, 1, 1 ); 450 fheroes2::updateShadow( font[193 - 32], { -1, 2 }, 2 ); 451 452 font[194 - 32] = font[34 + offset]; 453 454 font[195 - 32] = font[38]; 455 fheroes2::FillTransform( font[195 - 32], 6, 4, 3, 4, 1 ); 456 457 font[196 - 32] = font[36 + offset]; 458 459 font[197 - 32] = font[37 + offset]; 460 461 // x with | in the middle. 462 font[198 - 32].resize( font[56].width() + 1, font[56].height() ); 463 font[198 - 32].reset(); 464 fheroes2::Copy( font[56], 1, 0, font[198 - 32], 1, 0, 8, 11 ); 465 fheroes2::Copy( font[56], 9, 0, font[198 - 32], 10, 0, 6, 11 ); 466 fheroes2::Fill( font[198 - 32], 9, 1, 1, 9, font[198 - 32].image()[1 + font[198 - 32].width()] ); 467 font[198 - 32].setPosition( font[56].x(), font[56].y() ); 468 fheroes2::updateShadow( font[198 - 32], { -1, 2 }, 2 ); 469 470 font[199 - 32].resize( font[19].width() + 1, font[19].height() ); 471 font[199 - 32].reset(); 472 fheroes2::Copy( font[19], 1, 0, font[199 - 32], 1, 0, 5, 3 ); 473 fheroes2::Copy( font[19], 5, 0, font[199 - 32], 6, 0, 3, 4 ); 474 fheroes2::Copy( font[19], 3, 5, font[199 - 32], 4, 4, 5, 4 ); 475 fheroes2::Copy( font[19], 1, 8, font[199 - 32], 1, 8, 5, 3 ); 476 fheroes2::Copy( font[19], 5, 8, font[199 - 32], 6, 8, 3, 3 ); 477 fheroes2::FillTransform( font[199 - 32], 2, 6, 5, 3, 1 ); 478 font[199 - 32].setPosition( font[19].x(), font[19].y() ); 479 fheroes2::updateShadow( font[199 - 32], { -1, 2 }, 2 ); 480 481 // Reverted N. 482 font[200 - 32] = font[46]; 483 fheroes2::FillTransform( font[200 - 32], 6, 1, 5, 11, 1 ); 484 fheroes2::Copy( font[46], 6, 2, font[200 - 32], 6, 6, 1, 3 ); 485 fheroes2::Copy( font[46], 7, 3, font[200 - 32], 7, 5, 1, 3 ); 486 fheroes2::Copy( font[46], 8, 4, font[200 - 32], 8, 4, 1, 3 ); 487 fheroes2::Copy( font[46], 8, 4, font[200 - 32], 9, 3, 1, 3 ); 488 fheroes2::Copy( font[46], 8, 4, font[200 - 32], 10, 2, 1, 3 ); 489 fheroes2::Copy( font[46], 8, 4, font[200 - 32], 11, 1, 1, 3 ); 490 fheroes2::Copy( font[46], 11, 7, font[200 - 32], 11, 8, 1, 1 ); 491 fheroes2::Copy( font[46], 13, 9, font[200 - 32], 11, 9, 1, 1 ); 492 fheroes2::updateShadow( font[200 - 32], { -1, 2 }, 2 ); 493 494 font[201 - 32].resize( font[200 - 32].width(), font[200 - 32].height() + 3 ); 495 font[201 - 32].reset(); 496 fheroes2::Copy( font[200 - 32], 0, 0, font[201 - 32], 0, 3, font[200 - 32].width(), font[200 - 32].height() ); 497 font[201 - 32].setPosition( font[200 - 32].x(), font[200 - 32].y() - 3 ); 498 fheroes2::Copy( font[201 - 32], 12, 4, font[201 - 32], 8, 0, 1, 1 ); 499 fheroes2::Copy( font[201 - 32], 11, 10, font[201 - 32], 8, 1, 1, 1 ); 500 fheroes2::updateShadow( font[201 - 32], { -1, 2 }, 2 ); 501 502 font[202 - 32] = font[43 + offset]; 503 504 font[204 - 32] = font[45 + offset]; 505 font[205 - 32] = font[40 + offset]; 506 font[206 - 32] = font[47 + offset]; 507 508 font[207 - 32] = font[195 - 32]; 509 fheroes2::Copy( font[207 - 32], 4, 1, font[207 - 32], 8, 1, 2, 9 ); 510 fheroes2::Copy( font[207 - 32], 4, 9, font[207 - 32], 8, 10, 2, 1 ); 511 fheroes2::Copy( font[207 - 32], 6, 0, font[207 - 32], 10, 0, 1, 2 ); 512 fheroes2::updateShadow( font[207 - 32], { -1, 2 }, 2 ); 513 514 font[203 - 32].resize( font[207 - 32].width() - 1, font[207 - 32].height() ); 515 font[203 - 32].reset(); 516 fheroes2::Copy( font[207 - 32], 0, 0, font[203 - 32], 0, 0, font[207 - 32].width() - 1, font[207 - 32].height() ); 517 fheroes2::FillTransform( font[203 - 32], 0, 0, 4, 6, 1 ); 518 fheroes2::FillTransform( font[203 - 32], 4, 0, 3, 2, 1 ); 519 fheroes2::Copy( font[203 - 32], 4, 2, font[203 - 32], 5, 1, 2, 1 ); 520 fheroes2::Copy( font[203 - 32], 1, 10, font[203 - 32], 5, 0, 2, 1 ); 521 font[203 - 32].setPosition( font[207 - 32].x(), font[207 - 32].y() ); 522 fheroes2::updateShadow( font[203 - 32], { -1, 2 }, 2 ); 523 524 font[208 - 32] = font[48 + offset]; 525 font[209 - 32] = font[35 + offset]; 526 527 font[210 - 32].resize( font[207 - 32].width() + 4, font[207 - 32].height() ); 528 font[210 - 32].reset(); 529 fheroes2::Copy( font[207 - 32], 0, 0, font[210 - 32], 0, 0, font[207 - 32].width(), font[207 - 32].height() ); 530 fheroes2::Copy( font[210 - 32], 7, 0, font[210 - 32], 11, 0, 4, font[207 - 32].height() ); 531 font[210 - 32].setPosition( font[207 - 32].x(), font[207 - 32].y() ); 532 533 font[211 - 32] = font[57 + offset]; 534 535 font[212 - 32].resize( font[48].width() + 1, font[48].height() ); 536 font[212 - 32].reset(); 537 fheroes2::Copy( font[48], 0, 0, font[212 - 32], 1, 0, font[48].width(), font[48].height() ); 538 { 539 // TODO: add proper Flip function variant. 540 fheroes2::Sprite temp = fheroes2::Crop( font[48], 6, 0, 5, 6 ); 541 temp = fheroes2::Flip( temp, true, false ); 542 fheroes2::Copy( temp, 0, 0, font[212 - 32], 1, 0, temp.width(), temp.height() ); 543 } 544 font[212 - 32].setPosition( font[48].x(), font[48].y() ); 545 fheroes2::updateShadow( font[212 - 32], { -1, 2 }, 2 ); 546 547 font[213 - 32] = font[56 + offset]; 548 549 font[214 - 32].resize( font[53].width() + 2, font[53].height() + 1 ); 550 font[214 - 32].reset(); 551 fheroes2::Copy( font[53], 0, 0, font[214 - 32], 0, 0, font[52].width(), font[52].height() ); 552 fheroes2::Copy( font[214 - 32], 9, 1, font[214 - 32], 11, 9, 1, 1 ); 553 fheroes2::Copy( font[214 - 32], 9, 1, font[214 - 32], 12, 8, 1, 1 ); 554 fheroes2::Copy( font[214 - 32], 9, 1, font[214 - 32], 12, 10, 1, 2 ); 555 fheroes2::Copy( font[214 - 32], 10, 1, font[214 - 32], 12, 9, 1, 1 ); 556 fheroes2::Copy( font[214 - 32], 10, 1, font[214 - 32], 13, 8, 1, 4 ); 557 font[214 - 32].setPosition( font[53].x(), font[53].y() ); 558 fheroes2::updateShadow( font[214 - 32], { -1, 2 }, 2 ); 559 560 font[216 - 32].resize( font[53].width() + 2, font[53].height() ); 561 font[216 - 32].reset(); 562 fheroes2::Copy( font[53], 0, 0, font[216 - 32], 0, 0, 6, 11 ); 563 fheroes2::Copy( font[53], 8, 0, font[216 - 32], 7, 0, 3, 11 ); 564 fheroes2::Copy( font[53], 8, 0, font[216 - 32], 11, 0, 3, 11 ); 565 fheroes2::Copy( font[204 - 32], 10, 0, font[216 - 32], 6, 5, 3, 5 ); 566 fheroes2::Copy( font[204 - 32], 10, 0, font[216 - 32], 10, 5, 3, 5 ); 567 fheroes2::FillTransform( font[216 - 32], 7, 10, 1, 1, 1 ); 568 fheroes2::FillTransform( font[216 - 32], 11, 10, 1, 1, 1 ); 569 font[216 - 32].setPosition( font[53].x(), font[53].y() ); 570 fheroes2::updateShadow( font[216 - 32], { -1, 2 }, 2 ); 571 572 font[215 - 32] = font[53]; 573 fheroes2::FillTransform( font[215 - 32], 3, 6, 6, 7, 1 ); 574 fheroes2::Copy( font[216 - 32], 4, 5, font[215 - 32], 4, 3, 4, 6 ); 575 fheroes2::Copy( font[215 - 32], 6, 5, font[215 - 32], 8, 3, 1, 3 ); 576 fheroes2::Copy( font[215 - 32], 7, 4, font[215 - 32], 9, 2, 1, 2 ); 577 fheroes2::Copy( font[215 - 32], 9, 8, font[215 - 32], 9, 9, 1, 1 ); 578 fheroes2::updateShadow( font[215 - 32], { -1, 2 }, 2 ); 579 580 font[217 - 32].resize( font[216 - 32].width() + 2, font[216 - 32].height() + 1 ); 581 font[217 - 32].reset(); 582 fheroes2::Copy( font[216 - 32], 0, 0, font[217 - 32], 0, 0, font[216 - 32].width(), font[216 - 32].height() ); 583 fheroes2::Copy( font[214 - 32], 11, 8, font[217 - 32], 14, 8, 3, 4 ); 584 font[217 - 32].setPosition( font[216 - 32].x(), font[216 - 32].y() ); 585 fheroes2::updateShadow( font[217 - 32], { -1, 2 }, 2 ); 586 587 font[218 - 32].resize( font[193 - 32].width() + 1, font[193 - 32].height() ); 588 font[218 - 32].reset(); 589 fheroes2::Copy( font[193 - 32], 0, 0, font[218 - 32], 1, 0, font[193 - 32].width(), font[193 - 32].height() ); 590 fheroes2::Copy( font[193 - 32], 1, 0, font[218 - 32], 1, 0, 3, 4 ); 591 fheroes2::FillTransform( font[218 - 32], 7, 0, 5, 4, 1 ); 592 font[218 - 32].setPosition( font[193 - 32].x(), font[193 - 32].y() ); 593 fheroes2::updateShadow( font[218 - 32], { -1, 2 }, 2 ); 594 595 font[220 - 32] = font[193 - 32]; 596 fheroes2::FillTransform( font[220 - 32], 0, 0, 4, 6, 1 ); 597 fheroes2::FillTransform( font[220 - 32], 6, 0, 5, 4, 1 ); 598 fheroes2::Copy( font[53], 8, 0, font[220 - 32], 3, 0, 3, 1 ); 599 fheroes2::updateShadow( font[220 - 32], { -1, 2 }, 2 ); 600 601 font[219 - 32].resize( font[220 - 32].width() + 3, font[220 - 32].height() ); 602 font[219 - 32].reset(); 603 fheroes2::Copy( font[220 - 32], 0, 0, font[219 - 32], 0, 0, font[220 - 32].width(), font[220 - 32].height() ); 604 fheroes2::Copy( font[219 - 32], 3, 0, font[219 - 32], 11, 0, 3, 9 ); 605 fheroes2::Copy( font[207 - 32], 8, 9, font[219 - 32], 12, 9, 2, 2 ); 606 font[219 - 32].setPosition( font[220 - 32].x(), font[220 - 32].y() ); 607 fheroes2::updateShadow( font[219 - 32], { -1, 2 }, 2 ); 608 609 font[221 - 32].resize( font[47].width() - 3, font[47].height() ); 610 font[221 - 32].reset(); 611 fheroes2::Copy( font[47], 4, 0, font[221 - 32], 1, 0, 9, 11 ); 612 fheroes2::FillTransform( font[221 - 32], 0, 3, 3, 5, 1 ); 613 fheroes2::Copy( font[221 - 32], 3, 0, font[221 - 32], 4, 5, 5, 1 ); 614 font[221 - 32].setPosition( font[47].x(), font[47].y() ); 615 fheroes2::updateShadow( font[221 - 32], { -1, 2 }, 2 ); 616 617 font[222 - 32].resize( font[47].width() + 1, font[47].height() ); 618 font[222 - 32].reset(); 619 fheroes2::Copy( font[193 - 32], 0, 0, font[222 - 32], 0, 0, 6, 13 ); 620 fheroes2::Copy( font[47], 4, 1, font[222 - 32], 7, 1, 4, 8 ); 621 fheroes2::Copy( font[47], 10, 1, font[222 - 32], 11, 1, 3, 8 ); 622 fheroes2::Copy( font[47], 5, 0, font[222 - 32], 8, 0, 3, 1 ); 623 fheroes2::Copy( font[47], 10, 0, font[222 - 32], 11, 0, 2, 1 ); 624 fheroes2::Copy( font[47], 4, 9, font[222 - 32], 7, 9, 4, 2 ); 625 fheroes2::Copy( font[47], 10, 9, font[222 - 32], 11, 9, 3, 2 ); 626 fheroes2::Copy( font[222 - 32], 2, 0, font[222 - 32], 6, 5, 2, 1 ); 627 font[222 - 32].setPosition( font[193 - 32].x(), font[193 - 32].y() ); 628 fheroes2::updateShadow( font[222 - 32], { -1, 2 }, 2 ); 629 630 font[223 - 32].resize( font[203 - 32].width() - 1, font[203 - 32].height() ); 631 font[223 - 32].reset(); 632 fheroes2::Copy( font[33], 0, 5, font[223 - 32], 0, 5, 7, 6 ); 633 fheroes2::Copy( font[212 - 32], 0, 0, font[223 - 32], 1, 0, 7, 6 ); 634 fheroes2::Copy( font[203 - 32], 8, 0, font[223 - 32], 7, 0, 2, 11 ); 635 fheroes2::Copy( font[223 - 32], 6, 5, font[223 - 32], 7, 5, 1, 1 ); 636 font[223 - 32].setPosition( font[203 - 32].x(), font[203 - 32].y() ); 637 fheroes2::updateShadow( font[223 - 32], { -1, 2 }, 2 ); 638 639 offset = 32; 640 641 // e with 2 dots on top. 642 font[184 - 32] = font[37 + offset]; 643 644 font[224 - 32] = font[33 + offset]; 645 646 font[225 - 32].resize( font[69].width(), font[69].height() + 3 ); 647 font[225 - 32].reset(); 648 fheroes2::Copy( font[69], 1, 5, font[225 - 32], 1, 8, 8, 2 ); 649 fheroes2::Copy( font[69], 1, 0, font[225 - 32], 1, 6, 8, 2 ); 650 fheroes2::Copy( font[67], 1, 0, font[225 - 32], 1, 0, 8, 2 ); 651 fheroes2::Copy( font[45], 7, 3, font[225 - 32], 1, 2, 3, 1 ); 652 fheroes2::Copy( font[45], 7, 3, font[225 - 32], 2, 3, 3, 1 ); 653 fheroes2::Copy( font[45], 7, 3, font[225 - 32], 3, 4, 3, 1 ); 654 fheroes2::Copy( font[45], 8, 3, font[225 - 32], 6, 5, 2, 1 ); 655 fheroes2::Copy( font[45], 7, 3, font[225 - 32], 4, 5, 2, 1 ); 656 font[225 - 32].setPosition( font[69].x(), font[69].y() - 3 ); 657 fheroes2::updateShadow( font[225 - 32], { -1, 2 }, 2 ); 658 659 font[227 - 32] = font[82]; 660 fheroes2::Copy( font[227 - 32], 1, 0, font[227 - 32], 3, 0, 2, 1 ); 661 fheroes2::Copy( font[227 - 32], 4, 2, font[227 - 32], 4, 1, 1, 1 ); 662 fheroes2::SetTransformPixel( font[227 - 32], 4, 2, 1 ); 663 fheroes2::updateShadow( font[227 - 32], { -1, 2 }, 2 ); 664 665 font[228 - 32] = font[71]; 666 font[229 - 32] = font[37 + offset]; 667 668 // x with | in the middle. 669 font[230 - 32].resize( font[88].width() + 2, font[88].height() ); 670 font[230 - 32].reset(); 671 fheroes2::Copy( font[88], 0, 0, font[230 - 32], 0, 0, 6, 7 ); 672 fheroes2::Copy( font[88], 5, 0, font[230 - 32], 7, 0, 5, 7 ); 673 fheroes2::Fill( font[230 - 32], 6, 1, 1, 5, font[230 - 32].image()[3 + font[230 - 32].width()] ); 674 font[230 - 32].setPosition( font[88].x(), font[88].y() ); 675 fheroes2::updateShadow( font[230 - 32], { -1, 2 }, 2 ); 676 677 // letter 3 (z) 678 font[231 - 32].resize( font[19].width(), font[19].height() - 4 ); 679 font[231 - 32].reset(); 680 fheroes2::Copy( font[19], 0, 0, font[231 - 32], 0, 0, font[19].width(), 3 ); 681 fheroes2::Copy( font[19], 0, 5, font[231 - 32], 0, 3, font[19].width(), 1 ); 682 fheroes2::Copy( font[19], 0, 8, font[231 - 32], 0, 4, font[19].width(), 4 ); 683 fheroes2::FillTransform( font[231 - 32], 0, 2, 3, 3, 1 ); 684 font[231 - 32].setPosition( font[19].x(), font[19].y() + 4 ); 685 fheroes2::updateShadow( font[231 - 32], { -1, 2 }, 2 ); 686 687 // letter B (v) 688 font[226 - 32].resize( font[231 - 32].width() + 1, font[231 - 32].height() ); 689 font[226 - 32].reset(); 690 fheroes2::Copy( font[231 - 32], 0, 0, font[226 - 32], 1, 0, font[231 - 32].width(), font[231 - 32].height() ); 691 fheroes2::Copy( font[77], 1, 0, font[226 - 32], 1, 0, 3, 7 ); 692 fheroes2::Copy( font[226 - 32], 7, 1, font[226 - 32], 3, 0, 1, 1 ); 693 fheroes2::Copy( font[226 - 32], 7, 1, font[226 - 32], 3, 6, 1, 1 ); 694 fheroes2::Copy( font[226 - 32], 3, 4, font[226 - 32], 3, 5, 1, 1 ); 695 font[226 - 32].setPosition( font[231 - 32].x(), font[231 - 32].y() ); 696 fheroes2::updateShadow( font[226 - 32], { -1, 2 }, 2 ); 697 698 font[232 - 32] = font[85]; 699 700 font[233 - 32].resize( font[232 - 32].width(), font[232 - 32].height() + 3 ); 701 font[233 - 32].reset(); 702 fheroes2::Copy( font[232 - 32], 0, 0, font[233 - 32], 0, 3, font[232 - 32].width(), font[232 - 32].height() ); 703 fheroes2::Copy( font[233 - 32], 8, 3, font[233 - 32], 5, 0, 1, 1 ); 704 fheroes2::Copy( font[233 - 32], 7, 3, font[233 - 32], 5, 1, 1, 1 ); 705 font[233 - 32].setPosition( font[232 - 32].x(), font[232 - 32].y() - 3 ); 706 fheroes2::updateShadow( font[233 - 32], { -1, 2 }, 2 ); 707 708 // Shorter k. 709 font[234 - 32].resize( font[75].width(), font[75].height() - 4 ); 710 font[234 - 32].reset(); 711 fheroes2::Copy( font[75], 2, 2, font[234 - 32], 2, 0, 7, 4 ); 712 fheroes2::Copy( font[75], 1, 0, font[234 - 32], 1, 0, 3, 1 ); 713 fheroes2::Copy( font[75], 0, 7, font[234 - 32], 0, 4, font[75].width(), 2 ); 714 fheroes2::Copy( font[75], 0, 10, font[234 - 32], 0, 6, 4, 1 ); 715 fheroes2::Copy( font[75], 7, 10, font[234 - 32], 6, 6, 3, 1 ); 716 font[234 - 32].setPosition( font[75].x(), font[75].y() + 4 ); 717 fheroes2::updateShadow( font[234 - 32], { -1, 2 }, 2 ); 718 719 font[235 - 32] = font[78]; 720 fheroes2::Copy( font[235 - 32], 3, 0, font[235 - 32], 2, 1, 1, 1 ); 721 fheroes2::FillTransform( font[235 - 32], 0, 0, 2, 3, 1 ); 722 fheroes2::FillTransform( font[235 - 32], 2, 0, 1, 1, 1 ); 723 fheroes2::updateShadow( font[235 - 32], { -1, 2 }, 2 ); 724 725 font[236 - 32] = font[45 + offset]; 726 fheroes2::Copy( font[87], 9, 0, font[236 - 32], 3, 0, 4, 7 ); 727 fheroes2::Copy( font[87], 9, 0, font[236 - 32], 9, 0, 4, 7 ); 728 fheroes2::FillTransform( font[236 - 32], 0, 0, 3, 6, 1 ); 729 fheroes2::updateShadow( font[236 - 32], { -1, 2 }, 2 ); 730 731 font[237 - 32] = font[78]; 732 fheroes2::FillTransform( font[237 - 32], 4, 0, 3, 8, 1 ); 733 fheroes2::Copy( font[78], 4, 1, font[237 - 32], 4, 3, 1, 2 ); 734 fheroes2::Copy( font[78], 4, 1, font[237 - 32], 5, 3, 1, 2 ); 735 fheroes2::Copy( font[78], 4, 1, font[237 - 32], 6, 3, 1, 2 ); 736 fheroes2::Copy( font[78], 4, 1, font[237 - 32], 7, 3, 1, 1 ); 737 fheroes2::updateShadow( font[237 - 32], { -1, 2 }, 2 ); 738 739 font[238 - 32] = font[47 + offset]; 740 741 font[239 - 32] = font[78]; 742 743 font[240 - 32] = font[48 + offset]; 744 font[241 - 32] = font[35 + offset]; 745 font[242 - 32] = font[77]; 746 font[243 - 32] = font[57 + offset]; 747 748 font[244 - 32].resize( font[81].width(), font[81].height() ); 749 font[244 - 32].reset(); 750 fheroes2::Copy( font[80], 1, 0, font[244 - 32], 3, 0, 4, 10 ); 751 fheroes2::Copy( font[81], 0, 0, font[244 - 32], 0, 0, 5, 7 ); 752 fheroes2::Copy( font[80], 6, 0, font[244 - 32], 7, 0, 4, 7 ); 753 font[244 - 32].setPosition( font[81].x(), font[81].y() ); 754 fheroes2::updateShadow( font[244 - 32], { -1, 2 }, 2 ); 755 756 font[245 - 32] = font[56 + offset]; 757 758 font[246 - 32].resize( font[85].width() + 2, font[85].height() + 1 ); 759 font[246 - 32].reset(); 760 fheroes2::Copy( font[85], 0, 0, font[246 - 32], 0, 0, font[85].width(), font[85].height() ); 761 fheroes2::Copy( font[246 - 32], 7, 4, font[246 - 32], 9, 5, 1, 1 ); 762 fheroes2::Copy( font[246 - 32], 7, 4, font[246 - 32], 10, 4, 1, 1 ); 763 fheroes2::Copy( font[246 - 32], 8, 1, font[246 - 32], 11, 4, 1, 4 ); 764 fheroes2::Copy( font[246 - 32], 8, 1, font[246 - 32], 10, 5, 1, 1 ); 765 fheroes2::Copy( font[246 - 32], 9, 5, font[246 - 32], 10, 6, 1, 1 ); 766 fheroes2::Copy( font[246 - 32], 9, 5, font[246 - 32], 10, 7, 1, 1 ); 767 font[246 - 32].setPosition( font[85].x(), font[85].y() ); 768 fheroes2::updateShadow( font[246 - 32], { -1, 2 }, 2 ); 769 770 font[247 - 32] = font[85]; 771 fheroes2::Copy( font[247 - 32], 2, 5, font[247 - 32], 2, 3, 6, 2 ); 772 fheroes2::Copy( font[247 - 32], 8, 0, font[247 - 32], 7, 4, 1, 1 ); 773 fheroes2::Copy( font[247 - 32], 8, 0, font[247 - 32], 7, 5, 1, 1 ); 774 fheroes2::Copy( font[247 - 32], 8, 0, font[247 - 32], 7, 6, 1, 1 ); 775 fheroes2::FillTransform( font[247 - 32], 1, 5, 6, 4, 1 ); 776 fheroes2::updateShadow( font[247 - 32], { -1, 2 }, 2 ); 777 778 font[248 - 32].resize( font[85].width() + 3, font[85].height() ); 779 font[248 - 32].reset(); 780 fheroes2::Copy( font[85], 0, 0, font[248 - 32], 0, 0, 4, 7 ); 781 fheroes2::Copy( font[85], 1, 0, font[248 - 32], 5, 0, 4, 7 ); 782 fheroes2::Copy( font[85], 6, 0, font[248 - 32], 9, 0, 4, 7 ); 783 fheroes2::Copy( font[248 - 32], 8, 5, font[248 - 32], 4, 5, 4, 2 ); 784 font[248 - 32].setPosition( font[85].x(), font[85].y() ); 785 fheroes2::updateShadow( font[248 - 32], { -1, 2 }, 2 ); 786 787 font[249 - 32].resize( font[248 - 32].width() + 2, font[248 - 32].height() ); 788 font[249 - 32].reset(); 789 fheroes2::Copy( font[248 - 32], 0, 0, font[249 - 32], 0, 0, 12, 7 ); 790 fheroes2::Copy( font[246 - 32], 9, 4, font[249 - 32], 12, 4, 3, 4 ); 791 font[249 - 32].setPosition( font[248 - 32].x(), font[248 - 32].y() ); 792 fheroes2::updateShadow( font[249 - 32], { -1, 2 }, 2 ); 793 794 font[252 - 32] = font[226 - 32]; 795 fheroes2::FillTransform( font[252 - 32], 4, 0, 5, 3, 1 ); 796 797 font[250 - 32].resize( font[252 - 32].width() + 1, font[252 - 32].height() ); 798 font[250 - 32].reset(); 799 fheroes2::Copy( font[252 - 32], 0, 0, font[250 - 32], 1, 0, font[252 - 32].width(), font[252 - 32].height() ); 800 fheroes2::Copy( font[252 - 32], 1, 0, font[250 - 32], 1, 0, 1, 2 ); 801 font[250 - 32].setPosition( font[252 - 32].x(), font[252 - 32].y() ); 802 fheroes2::updateShadow( font[250 - 32], { -1, 2 }, 2 ); 803 804 font[251 - 32].resize( font[252 - 32].width() + 3, font[252 - 32].height() ); 805 font[251 - 32].reset(); 806 fheroes2::Copy( font[252 - 32], 0, 0, font[251 - 32], 0, 0, font[252 - 32].width(), font[252 - 32].height() ); 807 fheroes2::Copy( font[252 - 32], 2, 0, font[251 - 32], 10, 0, 2, 7 ); 808 font[251 - 32].setPosition( font[252 - 32].x(), font[252 - 32].y() ); 809 fheroes2::updateShadow( font[251 - 32], { -1, 2 }, 2 ); 810 811 font[253 - 32] = font[79]; 812 fheroes2::FillTransform( font[253 - 32], 0, 2, 3, 3, 1 ); 813 fheroes2::Copy( font[253 - 32], 8, 3, font[253 - 32], 7, 3, 1, 1 ); 814 fheroes2::Copy( font[253 - 32], 8, 3, font[253 - 32], 6, 3, 1, 1 ); 815 fheroes2::Copy( font[253 - 32], 8, 3, font[253 - 32], 5, 3, 1, 1 ); 816 fheroes2::updateShadow( font[253 - 32], { -1, 2 }, 2 ); 817 818 font[254 - 32].resize( font[79].width() + 1, font[79].height() ); 819 font[254 - 32].reset(); 820 fheroes2::Copy( font[251 - 32], 1, 0, font[254 - 32], 1, 0, 3, 7 ); 821 fheroes2::Copy( font[79], 2, 1, font[254 - 32], 6, 1, 1, 5 ); 822 fheroes2::Copy( font[79], 3, 0, font[254 - 32], 6, 0, 3, 2 ); 823 fheroes2::Copy( font[79], 7, 0, font[254 - 32], 9, 0, 1, 2 ); 824 fheroes2::Copy( font[79], 8, 2, font[254 - 32], 9, 2, 1, 3 ); 825 fheroes2::Copy( font[79], 7, 5, font[254 - 32], 9, 5, 1, 2 ); 826 fheroes2::Copy( font[79], 3, 6, font[254 - 32], 6, 6, 3, 1 ); 827 fheroes2::Copy( font[254 - 32], 1, 0, font[254 - 32], 4, 3, 2, 1 ); 828 font[254 - 32].setPosition( font[251 - 32].x(), font[251 - 32].y() ); 829 fheroes2::updateShadow( font[254 - 32], { -1, 2 }, 2 ); 830 831 font[255 - 32] = font[65]; 832 fheroes2::FillTransform( font[255 - 32], 0, 2, 6, 3, 1 ); 833 fheroes2::Copy( font[69], 2, 5, font[255 - 32], 1, 2, 6, 2 ); 834 fheroes2::Copy( font[255 - 32], 6, 4, font[255 - 32], 6, 3, 1, 1 ); 835 fheroes2::updateShadow( font[255 - 32], { -1, 2 }, 2 ); 836 } 837 838 // Small font. 839 { 840 std::vector<fheroes2::Sprite> & font = _icnVsSprite[ICN::SMALFONT]; 841 842 size_t offset = 0; 843 844 font[168 - 32] = font[37 + offset]; 845 846 font[192 - 32] = font[33 + offset]; 847 848 font[193 - 32] = font[34 + offset]; 849 fheroes2::FillTransform( font[193 - 32], 5, 1, 2, 2, 1 ); 850 fheroes2::Copy( font[193 - 32], 5, 0, font[193 - 32], 6, 0, 1, 1 ); 851 fheroes2::updateShadow( font[193 - 32], { -1, 1 }, 2 ); 852 853 font[194 - 32] = font[34 + offset]; 854 855 font[195 - 32].resize( font[193 - 32].width() + 1, font[193 - 32].height() ); 856 font[195 - 32].reset(); 857 fheroes2::Copy( font[193 - 32], 0, 0, font[195 - 32], 0, 0, 4, 8 ); 858 fheroes2::Copy( font[193 - 32], 3, 0, font[195 - 32], 4, 0, 4, 1 ); 859 font[195 - 32].setPosition( font[193 - 32].x(), font[193 - 32].y() ); 860 fheroes2::updateShadow( font[195 - 32], { -1, 1 }, 2 ); 861 862 font[196 - 32] = font[36 + offset]; 863 font[197 - 32] = font[37 + offset]; 864 865 font[198 - 32].resize( font[56].width() + 1, font[56].height() ); 866 font[198 - 32].reset(); 867 fheroes2::Copy( font[56], 1, 0, font[198 - 32], 1, 0, 3, 7 ); 868 fheroes2::Copy( font[56], 7, 0, font[198 - 32], 7, 0, 2, 7 ); 869 fheroes2::Copy( font[56], 4, 2, font[198 - 32], 3, 2, 1, 3 ); 870 fheroes2::Copy( font[56], 6, 2, font[198 - 32], 7, 2, 1, 3 ); 871 fheroes2::Copy( font[37], 4, 5, font[198 - 32], 4, 2, 3, 3 ); 872 fheroes2::Copy( font[37], 3, 0, font[198 - 32], 5, 0, 1, 7 ); 873 fheroes2::Copy( font[56], 8, 0, font[198 - 32], 9, 0, 1, 7 ); 874 font[198 - 32].setPosition( font[56].x(), font[56].y() ); 875 fheroes2::updateShadow( font[198 - 32], { -1, 1 }, 2 ); 876 877 font[199 - 32].resize( font[19].width() + 2, font[19].height() ); 878 font[199 - 32].reset(); 879 fheroes2::Copy( font[19], 1, 0, font[199 - 32], 1, 0, 3, 2 ); 880 fheroes2::Copy( font[19], 2, 0, font[199 - 32], 4, 0, 3, 2 ); 881 fheroes2::Copy( font[19], 2, 2, font[199 - 32], 3, 2, 3, 3 ); 882 fheroes2::Copy( font[19], 2, 5, font[199 - 32], 4, 5, 3, 2 ); 883 fheroes2::Copy( font[19], 1, 5, font[199 - 32], 1, 5, 3, 2 ); 884 fheroes2::FillTransform( font[199 - 32], 2, 4, 3, 2, 1 ); 885 fheroes2::FillTransform( font[199 - 32], 5, 5, 1, 1, 1 ); 886 fheroes2::FillTransform( font[199 - 32], 4, 2, 1, 1, 1 ); 887 font[199 - 32].setPosition( font[19].x(), font[19].y() ); 888 fheroes2::updateShadow( font[199 - 32], { -1, 1 }, 2 ); 889 890 font[200 - 32] = font[40]; 891 fheroes2::FillTransform( font[200 - 32], 4, 2, 3, 4, 1 ); 892 fheroes2::Copy( font[40], 3, 0, font[200 - 32], 4, 4, 1, 1 ); 893 fheroes2::Copy( font[40], 3, 0, font[200 - 32], 5, 3, 1, 1 ); 894 fheroes2::Copy( font[40], 3, 0, font[200 - 32], 6, 2, 1, 1 ); 895 fheroes2::updateShadow( font[200 - 32], { -1, 1 }, 2 ); 896 897 font[201 - 32].resize( font[200 - 32].width(), font[200 - 32].height() + 2 ); 898 font[201 - 32].reset(); 899 fheroes2::Copy( font[200 - 32], 1, 0, font[201 - 32], 1, 2, 8, 7 ); 900 fheroes2::Copy( font[200 - 32], 2, 0, font[201 - 32], 5, 0, 2, 1 ); 901 font[201 - 32].setPosition( font[200 - 32].x(), font[200 - 32].y() - 2 ); 902 fheroes2::updateShadow( font[201 - 32], { -1, 1 }, 2 ); 903 904 font[202 - 32] = font[43 + offset]; 905 906 font[203 - 32].resize( font[34].width(), font[34].height() ); 907 font[203 - 32].reset(); 908 fheroes2::Copy( font[34], 1, 0, font[203 - 32], 1, 0, 3, 7 ); 909 fheroes2::Copy( font[34], 3, 0, font[203 - 32], 6, 0, 1, 7 ); 910 fheroes2::Copy( font[34], 3, 0, font[203 - 32], 4, 0, 2, 1 ); 911 fheroes2::FillTransform( font[203 - 32], 1, 0, 2, 2, 1 ); 912 fheroes2::FillTransform( font[203 - 32], 3, 0, 1, 1, 1 ); 913 font[203 - 32].setPosition( font[34].x(), font[34].y() ); 914 fheroes2::updateShadow( font[203 - 32], { -1, 1 }, 2 ); 915 916 font[204 - 32] = font[45 + offset]; 917 font[205 - 32] = font[40 + offset]; 918 font[206 - 32] = font[47 + offset]; 919 920 font[207 - 32] = font[195 - 32]; 921 fheroes2::Copy( font[207 - 32], 3, 0, font[207 - 32], 6, 0, 1, 7 ); 922 fheroes2::updateShadow( font[207 - 32], { -1, 1 }, 2 ); 923 924 font[208 - 32] = font[48 + offset]; 925 font[209 - 32] = font[35 + offset]; 926 927 font[210 - 32].resize( font[207 - 32].width() + 2, font[207 - 32].height() ); 928 font[210 - 32].reset(); 929 fheroes2::Copy( font[207 - 32], 0, 0, font[210 - 32], 0, 0, font[207 - 32].width(), font[207 - 32].height() ); 930 fheroes2::Copy( font[210 - 32], 5, 0, font[210 - 32], 8, 0, 2, 8 ); 931 font[210 - 32].setPosition( font[207 - 32].x(), font[207 - 32].y() ); 932 933 font[211 - 32] = font[57 + offset]; 934 font[213 - 32] = font[56 + offset]; 935 936 font[214 - 32].resize( font[53].width(), font[53].height() + 1 ); 937 font[214 - 32].reset(); 938 fheroes2::Copy( font[53], 1, 0, font[214 - 32], 1, 0, 8, 7 ); 939 fheroes2::Copy( font[214 - 32], 3, 0, font[214 - 32], 9, 5, 1, 3 ); 940 font[214 - 32].setPosition( font[53].x(), font[53].y() ); 941 fheroes2::updateShadow( font[214 - 32], { -1, 1 }, 2 ); 942 943 font[215 - 32] = font[53]; 944 fheroes2::Copy( font[53], 3, 5, font[215 - 32], 3, 2, 4, 2 ); 945 fheroes2::FillTransform( font[215 - 32], 2, 4, 5, 4, 1 ); 946 fheroes2::updateShadow( font[215 - 32], { -1, 1 }, 2 ); 947 948 font[216 - 32].resize( font[53].width(), font[53].height() ); 949 font[216 - 32].reset(); 950 fheroes2::Copy( font[53], 1, 0, font[216 - 32], 1, 0, 4, 7 ); 951 fheroes2::Copy( font[53], 7, 1, font[216 - 32], 6, 1, 2, 6 ); 952 fheroes2::Copy( font[44], 3, 0, font[216 - 32], 9, 0, 1, 8 ); 953 fheroes2::Copy( font[53], 7, 1, font[216 - 32], 5, 5, 1, 1 ); 954 fheroes2::Copy( font[53], 7, 1, font[216 - 32], 8, 5, 1, 1 ); 955 fheroes2::Copy( font[53], 7, 1, font[216 - 32], 6, 0, 1, 1 ); 956 font[216 - 32].setPosition( font[53].x(), font[53].y() ); 957 fheroes2::updateShadow( font[216 - 32], { -1, 1 }, 2 ); 958 959 font[217 - 32].resize( font[216 - 32].width() + 2, font[216 - 32].height() + 1 ); 960 font[217 - 32].reset(); 961 fheroes2::Copy( font[216 - 32], 1, 0, font[217 - 32], 1, 0, 9, 7 ); 962 fheroes2::Copy( font[216 - 32], 3, 0, font[217 - 32], 10, 6, 1, 1 ); 963 fheroes2::Copy( font[216 - 32], 3, 0, font[217 - 32], 11, 5, 1, 3 ); 964 font[217 - 32].setPosition( font[216 - 32].x(), font[216 - 32].y() ); 965 fheroes2::updateShadow( font[217 - 32], { -1, 1 }, 2 ); 966 967 font[220 - 32].resize( font[34].width(), font[34].height() ); 968 font[220 - 32].reset(); 969 fheroes2::Copy( font[34], 2, 0, font[220 - 32], 1, 0, 2, 7 ); 970 fheroes2::Copy( font[34], 4, 3, font[220 - 32], 3, 3, 1, 4 ); 971 fheroes2::Copy( font[34], 4, 3, font[220 - 32], 4, 3, 3, 4 ); 972 fheroes2::FillTransform( font[220 - 32], 1, 0, 1, 1, 1 ); 973 font[220 - 32].setPosition( font[34].x(), font[34].y() ); 974 fheroes2::updateShadow( font[220 - 32], { -1, 1 }, 2 ); 975 976 font[219 - 32].resize( font[220 - 32].width() + 2, font[220 - 32].height() ); 977 font[219 - 32].reset(); 978 fheroes2::Copy( font[220 - 32], 1, 0, font[219 - 32], 1, 0, 6, 7 ); 979 fheroes2::Copy( font[220 - 32], 2, 0, font[219 - 32], 8, 0, 1, 7 ); 980 font[219 - 32].setPosition( font[220 - 32].x(), font[220 - 32].y() ); 981 fheroes2::updateShadow( font[219 - 32], { -1, 1 }, 2 ); 982 983 font[218 - 32].resize( font[220 - 32].width() + 2, font[220 - 32].height() ); 984 font[218 - 32].reset(); 985 fheroes2::Copy( font[220 - 32], 1, 0, font[218 - 32], 3, 0, 6, 7 ); 986 fheroes2::Copy( font[220 - 32], 2, 3, font[218 - 32], 1, 0, 3, 1 ); 987 fheroes2::Copy( font[220 - 32], 2, 3, font[218 - 32], 1, 1, 1, 1 ); 988 font[218 - 32].setPosition( font[220 - 32].x(), font[220 - 32].y() ); 989 fheroes2::updateShadow( font[218 - 32], { -1, 1 }, 2 ); 990 991 font[221 - 32].resize( font[47].width() - 1, font[47].height() ); 992 font[221 - 32].reset(); 993 fheroes2::Copy( font[47], 2, 0, font[221 - 32], 1, 0, 6, 7 ); 994 fheroes2::Copy( font[47], 3, 0, font[221 - 32], 4, 3, 2, 1 ); 995 font[221 - 32].setPosition( font[47].x(), font[47].y() ); 996 fheroes2::updateShadow( font[221 - 32], { -1, 1 }, 2 ); 997 998 font[222 - 32].resize( font[47].width() + 1, font[47].height() ); 999 font[222 - 32].reset(); 1000 fheroes2::Copy( font[44], 2, 0, font[222 - 32], 1, 0, 2, 7 ); 1001 fheroes2::Copy( font[47], 2, 0, font[222 - 32], 4, 0, 5, 2 ); 1002 fheroes2::Copy( font[47], 2, 5, font[222 - 32], 4, 5, 5, 2 ); 1003 fheroes2::Copy( font[222 - 32], 1, 0, font[222 - 32], 3, 3, 1, 1 ); 1004 fheroes2::Copy( font[222 - 32], 2, 0, font[222 - 32], 4, 2, 1, 3 ); 1005 fheroes2::Copy( font[222 - 32], 2, 0, font[222 - 32], 8, 2, 1, 3 ); 1006 font[222 - 32].setPosition( font[47].x(), font[47].y() ); 1007 fheroes2::updateShadow( font[222 - 32], { -1, 1 }, 2 ); 1008 1009 font[223 - 32].resize( font[48].width() - 1, font[48].height() ); 1010 font[223 - 32].reset(); 1011 fheroes2::Copy( font[48], 7, 1, font[223 - 32], 2, 1, 1, 2 ); 1012 fheroes2::Copy( font[48], 2, 0, font[223 - 32], 3, 0, 3, 1 ); 1013 fheroes2::Copy( font[48], 2, 0, font[223 - 32], 3, 3, 3, 1 ); 1014 fheroes2::Copy( font[44], 3, 0, font[223 - 32], 6, 0, 1, 7 ); 1015 fheroes2::Copy( font[33], 1, 6, font[223 - 32], 1, 6, 2, 1 ); 1016 fheroes2::Copy( font[33], 1, 6, font[223 - 32], 3, 5, 1, 1 ); 1017 fheroes2::Copy( font[33], 1, 6, font[223 - 32], 4, 4, 1, 1 ); 1018 font[223 - 32].setPosition( font[48].x(), font[48].y() ); 1019 fheroes2::updateShadow( font[223 - 32], { -1, 1 }, 2 ); 1020 1021 offset = 32; 1022 1023 font[184 - 32] = font[37 + offset]; 1024 1025 font[224 - 32] = font[33 + offset]; 1026 1027 font[225 - 32].resize( font[34].width(), font[34].height() ); 1028 font[225 - 32].reset(); 1029 fheroes2::Copy( font[34], 4, 3, font[225 - 32], 4, 3, 3, 4 ); 1030 fheroes2::Copy( font[65], 1, 2, font[225 - 32], 2, 4, 2, 3 ); 1031 fheroes2::FillTransform( font[225 - 32], 3, 5, 1, 1, 1 ); 1032 fheroes2::Copy( font[225 - 32], 2, 5, font[225 - 32], 2, 1, 2, 2 ); 1033 fheroes2::Copy( font[37], 2, 0, font[225 - 32], 2, 0, 5, 1 ); 1034 font[225 - 32].setPosition( font[34].x(), font[34].y() ); 1035 fheroes2::updateShadow( font[225 - 32], { -1, 1 }, 2 ); 1036 1037 font[226 - 32].resize( font[82].width() - 1, font[82].height() ); 1038 font[226 - 32].reset(); 1039 fheroes2::Copy( font[82], 1, 0, font[226 - 32], 1, 0, 2, 5 ); 1040 fheroes2::Copy( font[82], 1, 0, font[226 - 32], 3, 0, 2, 1 ); 1041 fheroes2::Copy( font[82], 1, 0, font[226 - 32], 3, 2, 2, 1 ); 1042 fheroes2::Copy( font[82], 1, 0, font[226 - 32], 3, 4, 2, 1 ); 1043 fheroes2::Copy( font[82], 1, 0, font[226 - 32], 5, 1, 1, 1 ); 1044 fheroes2::Copy( font[82], 1, 0, font[226 - 32], 5, 3, 1, 1 ); 1045 font[226 - 32].setPosition( font[82].x(), font[82].y() ); 1046 fheroes2::updateShadow( font[226 - 32], { -1, 1 }, 2 ); 1047 1048 font[227 - 32] = font[82]; 1049 fheroes2::Copy( font[227 - 32], 3, 1, font[227 - 32], 3, 0, 1, 1 ); 1050 fheroes2::FillTransform( font[227 - 32], 3, 1, 1, 1, 1 ); 1051 fheroes2::updateShadow( font[227 - 32], { -1, 1 }, 2 ); 1052 1053 font[228 - 32] = font[71]; 1054 1055 font[229 - 32] = font[37 + offset]; 1056 1057 font[230 - 32].resize( font[88].width() + 1, font[88].height() ); 1058 font[230 - 32].reset(); 1059 fheroes2::Copy( font[88], 0, 0, font[230 - 32], 0, 0, 4, 5 ); 1060 fheroes2::Copy( font[88], 4, 0, font[230 - 32], 5, 0, 4, 5 ); 1061 fheroes2::Copy( font[85], 2, 0, font[230 - 32], 4, 0, 1, 4 ); 1062 fheroes2::Copy( font[85], 2, 0, font[230 - 32], 4, 4, 1, 1 ); 1063 font[230 - 32].setPosition( font[88].x(), font[88].y() ); 1064 fheroes2::updateShadow( font[230 - 32], { -1, 1 }, 2 ); 1065 1066 font[232 - 32] = font[85]; 1067 1068 font[233 - 32].resize( font[232 - 32].width(), font[232 - 32].height() + 2 ); 1069 font[233 - 32].reset(); 1070 fheroes2::Copy( font[232 - 32], 1, 0, font[233 - 32], 1, 2, 7, 5 ); 1071 fheroes2::Copy( font[232 - 32], 1, 0, font[233 - 32], 3, 0, 2, 1 ); 1072 font[233 - 32].setPosition( font[232 - 32].x(), font[232 - 32].y() - 2 ); 1073 fheroes2::updateShadow( font[233 - 32], { -1, 1 }, 2 ); 1074 1075 font[234 - 32].resize( font[75].width() - 1, font[75].height() - 2 ); 1076 font[234 - 32].reset(); 1077 fheroes2::Copy( font[75], 1, 0, font[234 - 32], 1, 0, 2, 5 ); 1078 fheroes2::Copy( font[75], 4, 1, font[234 - 32], 3, 0, 3, 3 ); 1079 fheroes2::Copy( font[75], 5, 4, font[234 - 32], 4, 3, 2, 2 ); 1080 font[234 - 32].setPosition( font[75].x(), font[75].y() + 2 ); 1081 fheroes2::updateShadow( font[234 - 32], { -1, 1 }, 2 ); 1082 1083 font[235 - 32].resize( font[65].width() - 2, font[65].height() ); 1084 font[235 - 32].reset(); 1085 fheroes2::Copy( font[203 - 32], 2, 3, font[235 - 32], 1, 1, 2, 4 ); 1086 fheroes2::Copy( font[203 - 32], 5, 0, font[235 - 32], 3, 0, 2, 5 ); 1087 fheroes2::FillTransform( font[235 - 32], 1, 1, 1, 1, 1 ); 1088 font[235 - 32].setPosition( font[65].x(), font[65].y() ); 1089 fheroes2::updateShadow( font[235 - 32], { -1, 1 }, 2 ); 1090 1091 font[236 - 32].resize( font[235 - 32].width() + 3, font[235 - 32].height() ); 1092 font[236 - 32].reset(); 1093 fheroes2::Copy( font[235 - 32], 4, 0, font[236 - 32], 4, 0, 1, 5 ); 1094 fheroes2::Copy( font[235 - 32], 1, 0, font[236 - 32], 1, 1, 3, 3 ); 1095 fheroes2::Copy( font[236 - 32], 2, 0, font[236 - 32], 5, 0, 3, 5 ); 1096 fheroes2::Copy( font[236 - 32], 4, 0, font[236 - 32], 1, 4, 1, 1 ); 1097 font[236 - 32].setPosition( font[235 - 32].x(), font[235 - 32].y() ); 1098 fheroes2::updateShadow( font[236 - 32], { -1, 1 }, 2 ); 1099 1100 font[237 - 32].resize( font[72].width() - 2, font[72].height() - 2 ); 1101 font[237 - 32].reset(); 1102 fheroes2::Copy( font[72], 1, 0, font[237 - 32], 1, 0, 2, 5 ); 1103 fheroes2::Copy( font[72], 2, 0, font[237 - 32], 5, 0, 1, 5 ); 1104 fheroes2::Copy( font[72], 3, 2, font[237 - 32], 3, 2, 2, 1 ); 1105 font[237 - 32].setPosition( font[72].x(), font[72].y() + 2 ); 1106 fheroes2::updateShadow( font[237 - 32], { -1, 1 }, 2 ); 1107 1108 font[238 - 32] = font[47 + offset]; 1109 font[239 - 32] = font[78]; 1110 font[240 - 32] = font[48 + offset]; 1111 font[241 - 32] = font[35 + offset]; 1112 1113 font[242 - 32].resize( font[77].width() - 4, font[77].height() ); 1114 font[242 - 32].reset(); 1115 fheroes2::Copy( font[77], 1, 0, font[242 - 32], 1, 0, 2, 5 ); 1116 fheroes2::Copy( font[77], 6, 1, font[242 - 32], 4, 1, 1, 4 ); 1117 fheroes2::Copy( font[77], 10, 1, font[242 - 32], 6, 1, 2, 4 ); 1118 fheroes2::Copy( font[77], 3, 0, font[242 - 32], 2, 0, 3, 1 ); 1119 fheroes2::Copy( font[77], 3, 0, font[242 - 32], 5, 0, 1, 1 ); 1120 font[242 - 32].setPosition( font[77].x(), font[77].y() ); 1121 fheroes2::updateShadow( font[242 - 32], { -1, 1 }, 2 ); 1122 1123 font[243 - 32] = font[57 + offset]; 1124 1125 font[244 - 32].resize( font[81].width() + 3, font[81].height() + 1 ); 1126 font[244 - 32].reset(); 1127 fheroes2::Copy( font[81], 1, 0, font[244 - 32], 1, 0, 5, 7 ); 1128 fheroes2::Copy( font[81], 2, 0, font[244 - 32], 6, 0, 4, 4 ); 1129 fheroes2::Copy( font[81], 2, 4, font[244 - 32], 6, 4, 3, 1 ); 1130 fheroes2::Copy( font[81], 2, 4, font[244 - 32], 5, 7, 1, 1 ); 1131 font[244 - 32].setPosition( font[81].x(), font[81].y() ); 1132 fheroes2::updateShadow( font[244 - 32], { -1, 1 }, 2 ); 1133 1134 // Bigger letter 1135 font[212 - 32] = font[244 - 32]; 1136 fheroes2::Copy( font[212 - 32], 5, 1, font[212 - 32], 5, 0, 1, 1 ); 1137 fheroes2::Copy( font[212 - 32], 5, 1, font[212 - 32], 4, 7, 1, 1 ); 1138 font[212 - 32].setPosition( font[48].x(), font[48].y() ); // copy from a big better 1139 fheroes2::updateShadow( font[212 - 32], { -1, 1 }, 2 ); 1140 1141 font[245 - 32] = font[56 + offset]; 1142 1143 font[246 - 32].resize( font[85].width() + 1, font[85].height() + 1 ); 1144 font[246 - 32].reset(); 1145 fheroes2::Copy( font[85], 0, 0, font[246 - 32], 0, 0, font[85].width(), font[85].height() ); 1146 fheroes2::Copy( font[246 - 32], 2, 0, font[246 - 32], 8, 3, 1, 3 ); 1147 font[246 - 32].setPosition( font[85].x(), font[85].y() ); 1148 fheroes2::updateShadow( font[246 - 32], { -1, 1 }, 2 ); 1149 1150 font[247 - 32] = font[85]; 1151 fheroes2::Copy( font[85], 2, 4, font[247 - 32], 2, 2, 4, 1 ); 1152 fheroes2::Copy( font[85], 1, 0, font[247 - 32], 6, 4, 1, 1 ); 1153 fheroes2::FillTransform( font[247 - 32], 1, 3, 5, 3, 1 ); 1154 fheroes2::updateShadow( font[247 - 32], { -1, 1 }, 2 ); 1155 1156 font[248 - 32].resize( font[85].width() + 2, font[85].height() ); 1157 font[248 - 32].reset(); 1158 fheroes2::Copy( font[85], 1, 0, font[248 - 32], 1, 0, 3, 5 ); 1159 fheroes2::Copy( font[85], 6, 0, font[248 - 32], 5, 0, 2, 5 ); 1160 fheroes2::Copy( font[85], 6, 0, font[248 - 32], 8, 0, 2, 5 ); 1161 fheroes2::Copy( font[85], 1, 0, font[248 - 32], 4, 4, 1, 1 ); 1162 fheroes2::Copy( font[85], 1, 0, font[248 - 32], 7, 4, 1, 1 ); 1163 font[248 - 32].setPosition( font[85].x(), font[85].y() ); 1164 fheroes2::updateShadow( font[248 - 32], { -1, 1 }, 2 ); 1165 1166 font[249 - 32].resize( font[248 - 32].width() + 1, font[248 - 32].height() ); 1167 font[249 - 32].reset(); 1168 fheroes2::Copy( font[248 - 32], 1, 0, font[249 - 32], 1, 0, 9, 5 ); 1169 fheroes2::Copy( font[248 - 32], 2, 0, font[249 - 32], 10, 3, 1, 3 ); 1170 font[249 - 32].setPosition( font[248 - 32].x(), font[248 - 32].y() ); 1171 fheroes2::updateShadow( font[249 - 32], { -1, 1 }, 2 ); 1172 1173 font[252 - 32] = font[226 - 32]; 1174 fheroes2::Copy( font[252 - 32], 1, 0, font[252 - 32], 5, 4, 1, 1 ); 1175 fheroes2::FillTransform( font[252 - 32], 0, 0, 2, 2, 1 ); 1176 fheroes2::FillTransform( font[252 - 32], 3, 0, 3, 2, 1 ); 1177 1178 font[250 - 32].resize( font[252 - 32].width() + 1, font[252 - 32].height() ); 1179 font[250 - 32].reset(); 1180 fheroes2::Copy( font[252 - 32], 1, 0, font[250 - 32], 2, 0, 5, 5 ); 1181 fheroes2::Copy( font[252 - 32], 2, 2, font[250 - 32], 1, 0, 2, 1 ); 1182 fheroes2::Copy( font[252 - 32], 2, 2, font[250 - 32], 1, 1, 1, 1 ); 1183 font[250 - 32].setPosition( font[252 - 32].x(), font[252 - 32].y() ); 1184 fheroes2::updateShadow( font[250 - 32], { -1, 1 }, 2 ); 1185 1186 font[251 - 32].resize( font[252 - 32].width() + 2, font[252 - 32].height() ); 1187 font[251 - 32].reset(); 1188 fheroes2::Copy( font[252 - 32], 1, 0, font[251 - 32], 1, 0, 5, 5 ); 1189 fheroes2::Copy( font[252 - 32], 2, 0, font[251 - 32], 7, 0, 1, 5 ); 1190 font[251 - 32].setPosition( font[252 - 32].x(), font[252 - 32].y() ); 1191 fheroes2::updateShadow( font[251 - 32], { -1, 1 }, 2 ); 1192 1193 font[253 - 32].resize( font[79].width() - 1, font[79].height() ); 1194 font[253 - 32].reset(); 1195 fheroes2::Copy( font[79], 2, 0, font[253 - 32], 1, 0, 4, 5 ); 1196 fheroes2::Copy( font[79], 2, 0, font[253 - 32], 2, 2, 2, 1 ); 1197 font[253 - 32].setPosition( font[79].x(), font[79].y() ); 1198 fheroes2::updateShadow( font[253 - 32], { -1, 1 }, 2 ); 1199 1200 font[231 - 32] = font[253 - 32]; 1201 fheroes2::FillTransform( font[231 - 32], 0, 1, 3, 3, 1 ); 1202 fheroes2::FillTransform( font[231 - 32], 4, 2, 1, 1, 1 ); 1203 fheroes2::FillTransform( font[231 - 32], 1, 0, 1, 1, 1 ); 1204 fheroes2::Copy( font[253 - 32], 1, 0, font[231 - 32], 1, 1, 1, 1 ); 1205 fheroes2::updateShadow( font[231 - 32], { -1, 1 }, 2 ); 1206 1207 font[254 - 32].resize( font[79].width() + 2, font[79].height() ); 1208 font[254 - 32].reset(); 1209 fheroes2::Copy( font[82], 1, 0, font[254 - 32], 1, 0, 2, 5 ); 1210 fheroes2::Copy( font[79], 1, 0, font[254 - 32], 4, 0, 3, 5 ); 1211 fheroes2::Copy( font[79], 5, 1, font[254 - 32], 7, 1, 1, 3 ); 1212 fheroes2::Copy( font[79], 5, 1, font[254 - 32], 3, 2, 1, 1 ); 1213 font[254 - 32].setPosition( font[79].x(), font[79].y() ); 1214 fheroes2::updateShadow( font[254 - 32], { -1, 1 }, 2 ); 1215 1216 font[255 - 32].resize( font[65].width() - 1, font[65].height() ); 1217 font[255 - 32].reset(); 1218 fheroes2::Copy( font[65], 1, 2, font[255 - 32], 2, 0, 3, 3 ); 1219 fheroes2::Copy( font[235 - 32], 4, 0, font[255 - 32], 5, 0, 1, 5 ); 1220 fheroes2::Copy( font[33], 1, 5, font[255 - 32], 1, 3, 3, 2 ); 1221 font[255 - 32].setPosition( font[65].x(), font[65].y() ); 1222 fheroes2::updateShadow( font[255 - 32], { -1, 1 }, 2 ); 1223 } 1224 } 1225 generateAlphabet(const fheroes2::SupportedLanguage language)1226 void generateAlphabet( const fheroes2::SupportedLanguage language ) 1227 { 1228 switch ( language ) { 1229 case fheroes2::SupportedLanguage::Polish: 1230 generatePolishAlphabet(); 1231 break; 1232 case fheroes2::SupportedLanguage::German: 1233 generateGermanAlphabet(); 1234 break; 1235 case fheroes2::SupportedLanguage::French: 1236 generateFrenchAlphabet(); 1237 break; 1238 case fheroes2::SupportedLanguage::Russian: 1239 generateRussianAlphabet(); 1240 break; 1241 default: 1242 // Add new language generation code! 1243 assert( 0 ); 1244 break; 1245 } 1246 1247 _icnVsSprite[ICN::YELLOW_FONT].clear(); 1248 _icnVsSprite[ICN::YELLOW_SMALLFONT].clear(); 1249 _icnVsSprite[ICN::GRAY_FONT].clear(); 1250 _icnVsSprite[ICN::GRAY_SMALL_FONT].clear(); 1251 _icnVsSprite[ICN::WHITE_LARGE_FONT].clear(); 1252 } 1253 invertTransparency(fheroes2::Image & image)1254 void invertTransparency( fheroes2::Image & image ) 1255 { 1256 if ( image.singleLayer() ) { 1257 assert( 0 ); 1258 return; 1259 } 1260 1261 uint8_t * transform = image.transform(); 1262 uint8_t * transformEnd = transform + image.width() * image.height(); 1263 for ( ; transform != transformEnd; ++transform ) { 1264 if ( *transform == 0 ) { 1265 *transform = 1; 1266 } 1267 else if ( *transform == 1 ) { 1268 *transform = 0; 1269 } 1270 // Other transform values are not relevant for transparency checks. 1271 } 1272 } 1273 } 1274 1275 namespace fheroes2 1276 { 1277 namespace AGG 1278 { LoadOriginalICN(int id)1279 void LoadOriginalICN( int id ) 1280 { 1281 const std::vector<uint8_t> & body = ::AGG::ReadChunk( ICN::GetString( id ) ); 1282 1283 if ( body.empty() ) { 1284 return; 1285 } 1286 1287 StreamBuf imageStream( body ); 1288 1289 const uint32_t count = imageStream.getLE16(); 1290 const uint32_t blockSize = imageStream.getLE32(); 1291 if ( count == 0 || blockSize == 0 ) { 1292 return; 1293 } 1294 1295 _icnVsSprite[id].resize( count ); 1296 1297 for ( uint32_t i = 0; i < count; ++i ) { 1298 imageStream.seek( headerSize + i * 13 ); 1299 1300 ICNHeader header1; 1301 imageStream >> header1; 1302 1303 uint32_t sizeData = 0; 1304 if ( i + 1 != count ) { 1305 ICNHeader header2; 1306 imageStream >> header2; 1307 sizeData = header2.offsetData - header1.offsetData; 1308 } 1309 else { 1310 sizeData = blockSize - header1.offsetData; 1311 } 1312 1313 const uint8_t * data = body.data() + headerSize + header1.offsetData; 1314 1315 _icnVsSprite[id][i] 1316 = decodeICNSprite( data, sizeData, header1.width, header1.height, static_cast<int16_t>( header1.offsetX ), static_cast<int16_t>( header1.offsetY ) ); 1317 } 1318 } 1319 1320 // Helper function for LoadModifiedICN CopyICNWithPalette(int icnId,int originalIcnId,const PAL::PaletteType paletteType)1321 void CopyICNWithPalette( int icnId, int originalIcnId, const PAL::PaletteType paletteType ) 1322 { 1323 assert( icnId != originalIcnId ); 1324 1325 GetICN( originalIcnId, 0 ); // always avoid calling LoadOriginalICN directly 1326 1327 _icnVsSprite[icnId] = _icnVsSprite[originalIcnId]; 1328 const std::vector<uint8_t> & palette = PAL::GetPalette( paletteType ); 1329 for ( size_t i = 0; i < _icnVsSprite[icnId].size(); ++i ) { 1330 ApplyPalette( _icnVsSprite[icnId][i], palette ); 1331 } 1332 } 1333 LoadModifiedICN(int id)1334 bool LoadModifiedICN( int id ) 1335 { 1336 switch ( id ) { 1337 case ICN::ROUTERED: 1338 CopyICNWithPalette( id, ICN::ROUTE, PAL::PaletteType::RED ); 1339 return true; 1340 case ICN::FONT: 1341 case ICN::SMALFONT: { 1342 LoadOriginalICN( id ); 1343 auto & imageArray = _icnVsSprite[id]; 1344 if ( id == ICN::FONT ) { 1345 // The original images contain an issue: image layer has value 50 which is '2' in UTF-8. We must correct these (only 3) places 1346 for ( size_t i = 0; i < imageArray.size(); ++i ) { 1347 ReplaceColorIdByTransformId( imageArray[i], 50, 2 ); 1348 } 1349 } 1350 1351 // Some checks that we really have CP1251 font 1352 const int32_t verifiedFontWidth = ( id == ICN::FONT ) ? 19 : 12; 1353 if ( imageArray.size() == 162 && imageArray[121].width() == verifiedFontWidth ) { 1354 // Engine expects that letter indexes correspond to charcode - 0x20. 1355 // In case CP1251 font.icn contains sprites for chars 0x20-0x7F, 0xC0-0xDF, 0xA8, 0xE0-0xFF, 0xB8 (in that order). 1356 // We rearrange sprites array for corresponding sprite indexes to charcode - 0x20. 1357 imageArray.insert( imageArray.begin() + 96, 64, imageArray[0] ); 1358 std::swap( imageArray[136], imageArray[192] ); // Move sprites for chars 0xA8 1359 std::swap( imageArray[152], imageArray[225] ); // and 0xB8 to it's places. 1360 imageArray.pop_back(); 1361 imageArray.erase( imageArray.begin() + 192 ); 1362 } 1363 return true; 1364 } 1365 case ICN::YELLOW_FONT: 1366 CopyICNWithPalette( id, ICN::FONT, PAL::PaletteType::YELLOW_TEXT ); 1367 return true; 1368 case ICN::YELLOW_SMALLFONT: 1369 CopyICNWithPalette( id, ICN::SMALFONT, PAL::PaletteType::YELLOW_TEXT ); 1370 return true; 1371 case ICN::GRAY_FONT: 1372 CopyICNWithPalette( id, ICN::FONT, PAL::PaletteType::GRAY_TEXT ); 1373 return true; 1374 case ICN::GRAY_SMALL_FONT: 1375 CopyICNWithPalette( id, ICN::SMALFONT, PAL::PaletteType::GRAY_TEXT ); 1376 return true; 1377 case ICN::BTNBATTLEONLY: 1378 _icnVsSprite[id].resize( 2 ); 1379 for ( uint32_t i = 0; i < static_cast<uint32_t>( _icnVsSprite[id].size() ); ++i ) { 1380 Sprite & out = _icnVsSprite[id][i]; 1381 out = GetICN( ICN::BTNNEWGM, 6 + i ); 1382 // clean the button 1383 Image uniform( 83, 23 ); 1384 uniform.fill( ( i == 0 ) ? GetColorId( 216, 184, 152 ) : GetColorId( 184, 136, 96 ) ); 1385 Copy( uniform, 0, 0, out, 28, 18, uniform.width(), uniform.height() ); 1386 // add 'ba' 1387 Blit( GetICN( ICN::BTNCMPGN, i ), 41 - i, 28, out, 30 - i, 13, 28, 14 ); 1388 // add 'tt' 1389 Blit( GetICN( ICN::BTNNEWGM, i ), 25 - i, 13, out, 57 - i, 13, 13, 14 ); 1390 Blit( GetICN( ICN::BTNNEWGM, i ), 25 - i, 13, out, 70 - i, 13, 13, 14 ); 1391 // add 'le' 1392 Blit( GetICN( ICN::BTNNEWGM, 6 + i ), 97 - i, 21, out, 83 - i, 13, 13, 14 ); 1393 Blit( GetICN( ICN::BTNNEWGM, 6 + i ), 86 - i, 21, out, 96 - i, 13, 13, 14 ); 1394 // add 'on' 1395 Blit( GetICN( ICN::BTNDCCFG, 4 + i ), 44 - i, 21, out, 40 - i, 28, 31, 14 ); 1396 // add 'ly' 1397 Blit( GetICN( ICN::BTNHOTST, i ), 47 - i, 21, out, 71 - i, 28, 12, 13 ); 1398 Blit( GetICN( ICN::BTNHOTST, i ), 72 - i, 21, out, 84 - i, 28, 13, 13 ); 1399 } 1400 return true; 1401 case ICN::NON_UNIFORM_GOOD_MIN_BUTTON: 1402 _icnVsSprite[id].resize( 2 ); 1403 for ( uint32_t i = 0; i < static_cast<uint32_t>( _icnVsSprite[id].size() ); ++i ) { 1404 Sprite & out = _icnVsSprite[id][i]; 1405 out = GetICN( ICN::RECRUIT, 4 + i ); 1406 // clean the button 1407 Blit( GetICN( ICN::SYSTEM, 11 + i ), 10, 6 + i, out, 30 - 2 * i, 5 + i, 31, 15 ); 1408 // add 'IN' 1409 Copy( GetICN( ICN::APANEL, 4 + i ), 23 - i, 22 + i, out, 33 - i, 6 + i, 8, 14 ); // letter 'I' 1410 Copy( GetICN( ICN::APANEL, 4 + i ), 31 - i, 22 + i, out, 44 - i, 6 + i, 17, 14 ); // letter 'N' 1411 } 1412 return true; 1413 case ICN::SPELLS: 1414 LoadOriginalICN( id ); 1415 _icnVsSprite[id].resize( 66 ); 1416 for ( uint32_t i = 60; i < 66; ++i ) { 1417 int originalIndex = 0; 1418 if ( i == 60 ) // Mass Cure 1419 originalIndex = 6; 1420 else if ( i == 61 ) // Mass Haste 1421 originalIndex = 14; 1422 else if ( i == 62 ) // Mass Slow 1423 originalIndex = 1; 1424 else if ( i == 63 ) // Mass Bless 1425 originalIndex = 7; 1426 else if ( i == 64 ) // Mass Curse 1427 originalIndex = 3; 1428 else if ( i == 65 ) // Mass Shield 1429 originalIndex = 15; 1430 1431 const Sprite & originalImage = _icnVsSprite[id][originalIndex]; 1432 Sprite & image = _icnVsSprite[id][i]; 1433 1434 image.resize( originalImage.width() + 8, originalImage.height() + 8 ); 1435 image.setPosition( originalImage.x() + 4, originalImage.y() + 4 ); 1436 image.fill( 1 ); 1437 1438 AlphaBlit( originalImage, image, 0, 0, 128 ); 1439 AlphaBlit( originalImage, image, 4, 4, 192 ); 1440 Blit( originalImage, image, 8, 8 ); 1441 1442 AddTransparency( image, 1 ); 1443 } 1444 return true; 1445 case ICN::CSLMARKER: 1446 _icnVsSprite[id].resize( 3 ); 1447 for ( uint32_t i = 0; i < 3; ++i ) { 1448 _icnVsSprite[id][i] = GetICN( ICN::LOCATORS, 24 ); 1449 if ( i == 1 ) { 1450 ReplaceColorId( _icnVsSprite[id][i], 0x0A, 0xD6 ); 1451 } 1452 else if ( i == 2 ) { 1453 ReplaceColorId( _icnVsSprite[id][i], 0x0A, 0xDE ); 1454 } 1455 } 1456 return true; 1457 case ICN::BATTLESKIP: 1458 _icnVsSprite[id].resize( 2 ); 1459 for ( uint32_t i = 0; i < 2; ++i ) { 1460 Sprite & out = _icnVsSprite[id][i]; 1461 out = GetICN( ICN::TEXTBAR, 4 + i ); 1462 1463 // clean the button 1464 Blit( GetICN( ICN::SYSTEM, 11 + i ), 3, 8, out, 3, 1, 43, 14 ); 1465 1466 // add 'skip' 1467 Blit( GetICN( ICN::TEXTBAR, i ), 3, 10, out, 3, 0, 43, 14 ); 1468 } 1469 return true; 1470 case ICN::BATTLEWAIT: 1471 _icnVsSprite[id].resize( 2 ); 1472 for ( uint32_t i = 0; i < 2; ++i ) { 1473 Sprite & out = _icnVsSprite[id][i]; 1474 out = GetICN( ICN::TEXTBAR, 4 + i ); 1475 1476 // clean the button 1477 Blit( GetICN( ICN::SYSTEM, 11 + i ), 3, 8, out, 3, 1, 43, 14 ); 1478 1479 // add 'wait' 1480 const Sprite wait = Crop( GetICN( ICN::ADVBTNS, 8 + i ), 5, 4, 28, 28 ); 1481 Image resizedWait( wait.width() / 2, wait.height() / 2 ); 1482 Resize( wait, resizedWait ); 1483 1484 Blit( resizedWait, 0, 0, out, ( out.width() - 14 ) / 2, 0, 14, 14 ); 1485 } 1486 return true; 1487 case ICN::BUYMAX: 1488 _icnVsSprite[id].resize( 2 ); 1489 for ( uint32_t i = 0; i < 2; ++i ) { 1490 Sprite & out = _icnVsSprite[id][i]; 1491 out = GetICN( ICN::WELLXTRA, i ); 1492 1493 // clean the button 1494 Blit( GetICN( ICN::SYSTEM, 11 + i ), 10, 6, out, 6, 2, 52, 14 ); 1495 1496 // add 'max' 1497 Blit( GetICN( ICN::RECRUIT, 4 + i ), 12, 6, out, 7, 3, 50, 12 ); 1498 } 1499 return true; 1500 case ICN::BTNGIFT_GOOD: 1501 _icnVsSprite[id].resize( 2 ); 1502 for ( uint32_t i = 0; i < 2; ++i ) { 1503 Sprite & out = _icnVsSprite[id][i]; 1504 out = GetICN( ICN::TRADPOST, 17 + i ); 1505 1506 // clean the button 1507 Blit( GetICN( ICN::SYSTEM, 11 + i ), 10, 6, out, 6, 4, 72, 15 ); 1508 1509 // add 'G' 1510 Blit( GetICN( ICN::CPANEL, i ), 18 - i, 27, out, 20 - i, 4, 15, 15 ); 1511 1512 // add 'I' 1513 Blit( GetICN( ICN::APANEL, 4 + i ), 22 - i, 20, out, 36 - i, 4, 9, 15 ); 1514 1515 // add 'F' 1516 Blit( GetICN( ICN::APANEL, 4 + i ), 48 - i, 20, out, 46 - i, 4, 13, 15 ); 1517 1518 // add 'T' 1519 Blit( GetICN( ICN::CPANEL, 6 + i ), 59 - i, 21, out, 60 - i, 5, 14, 14 ); 1520 } 1521 return true; 1522 case ICN::BTNGIFT_EVIL: 1523 _icnVsSprite[id].resize( 2 ); 1524 for ( uint32_t i = 0; i < 2; ++i ) { 1525 Sprite & out = _icnVsSprite[id][i]; 1526 out = GetICN( ICN::TRADPOSE, 17 + i ); 1527 1528 // clean the button 1529 Blit( GetICN( ICN::SYSTEME, 11 + i ), 10, 6, out, 6, 4, 72, 15 ); 1530 1531 // add 'G' 1532 Blit( GetICN( ICN::CPANELE, i ), 18 - i, 27, out, 20 - i, 4, 15, 15 ); 1533 1534 // add 'I' 1535 Blit( GetICN( ICN::APANELE, 4 + i ), 22 - i, 20, out, 36 - i, 4, 9, 15 ); 1536 1537 // add 'F' 1538 Blit( GetICN( ICN::APANELE, 4 + i ), 48 - i, 20, out, 46 - i, 4, 13, 15 ); 1539 1540 // add 'T' 1541 Blit( GetICN( ICN::CPANELE, 6 + i ), 59 - i, 21, out, 60 - i, 5, 14, 14 ); 1542 } 1543 return true; 1544 case ICN::BTNCONFIG: 1545 _icnVsSprite[id].resize( 2 ); 1546 for ( uint32_t i = 0; i < 2; ++i ) { 1547 Sprite & out = _icnVsSprite[id][i]; 1548 out = GetICN( ICN::NON_UNIFORM_GOOD_OKAY_BUTTON, i ); 1549 1550 // add 'config' 1551 Blit( GetICN( ICN::BTNDCCFG, 4 + i ), 31 - i, 20, out, 10 - i, 4, 77, 16 ); 1552 } 1553 return true; 1554 case ICN::PHOENIX: 1555 LoadOriginalICN( id ); 1556 // First sprite has cropped shadow. We copy missing part from another 'almost' identical frame 1557 if ( _icnVsSprite[id].size() >= 32 ) { 1558 const Sprite & in = _icnVsSprite[id][32]; 1559 Copy( in, 60, 73, _icnVsSprite[id][1], 60, 73, 14, 13 ); 1560 Copy( in, 56, 72, _icnVsSprite[id][30], 56, 72, 18, 9 ); 1561 } 1562 return true; 1563 case ICN::MONH0028: // phoenix 1564 LoadOriginalICN( id ); 1565 if ( _icnVsSprite[id].size() == 1 ) { 1566 const Sprite & correctFrame = GetICN( ICN::PHOENIX, 32 ); 1567 Copy( correctFrame, 60, 73, _icnVsSprite[id][0], 58, 70, 14, 13 ); 1568 } 1569 return true; 1570 case ICN::CAVALRYR: 1571 LoadOriginalICN( id ); 1572 // Sprite 23 has incorrect colors, we need to replace them 1573 if ( _icnVsSprite[id].size() >= 23 ) { 1574 Sprite & out = _icnVsSprite[id][23]; 1575 1576 std::vector<uint8_t> indexes( 256 ); 1577 for ( uint32_t i = 0; i < 256; ++i ) { 1578 indexes[i] = static_cast<uint8_t>( i ); 1579 } 1580 1581 indexes[69] = 187; 1582 indexes[71] = 195; 1583 indexes[73] = 188; 1584 indexes[74] = 190; 1585 indexes[75] = 193; 1586 indexes[76] = 191; 1587 indexes[77] = 195; 1588 indexes[80] = 195; 1589 indexes[81] = 196; 1590 indexes[83] = 196; 1591 indexes[84] = 197; 1592 indexes[151] = 197; 1593 1594 ApplyPalette( out, indexes ); 1595 } 1596 return true; 1597 case ICN::TROLLMSL: 1598 LoadOriginalICN( id ); 1599 if ( _icnVsSprite[id].size() == 1 ) { 1600 Sprite & out = _icnVsSprite[id][0]; 1601 // The original sprite contains 2 pixels which are empty 1602 if ( out.width() * out.height() > 188 && out.transform()[147] == 1 && out.transform()[188] == 1 ) { 1603 out.transform()[147] = 0; 1604 out.image()[147] = 22; 1605 1606 out.transform()[188] = 0; 1607 out.image()[188] = 24; 1608 } 1609 } 1610 return true; 1611 case ICN::TROLL2MSL: 1612 LoadOriginalICN( ICN::TROLLMSL ); 1613 if ( _icnVsSprite[ICN::TROLLMSL].size() == 1 ) { 1614 _icnVsSprite[id].resize( 1 ); 1615 1616 Sprite & out = _icnVsSprite[id][0]; 1617 out = _icnVsSprite[ICN::TROLLMSL][0]; 1618 1619 // The original sprite contains 2 pixels which are empty 1620 if ( out.width() * out.height() > 188 && out.transform()[147] == 1 && out.transform()[188] == 1 ) { 1621 out.transform()[147] = 0; 1622 out.image()[147] = 22; 1623 1624 out.transform()[188] = 0; 1625 out.image()[188] = 24; 1626 } 1627 1628 std::vector<uint8_t> indexes( 256 ); 1629 for ( uint32_t i = 0; i < 256; ++i ) { 1630 indexes[i] = static_cast<uint8_t>( i ); 1631 } 1632 1633 indexes[10] = 152; 1634 indexes[11] = 153; 1635 indexes[12] = 154; 1636 indexes[13] = 155; 1637 indexes[14] = 155; 1638 indexes[15] = 156; 1639 indexes[16] = 157; 1640 indexes[17] = 158; 1641 indexes[18] = 159; 1642 indexes[19] = 160; 1643 indexes[20] = 160; 1644 indexes[21] = 161; 1645 indexes[22] = 162; 1646 indexes[23] = 163; 1647 indexes[24] = 164; 1648 indexes[25] = 165; 1649 indexes[26] = 166; 1650 indexes[27] = 166; 1651 indexes[28] = 167; 1652 indexes[29] = 168; 1653 indexes[30] = 169; 1654 indexes[31] = 170; 1655 indexes[32] = 171; 1656 indexes[33] = 172; 1657 indexes[34] = 172; 1658 indexes[35] = 173; 1659 1660 ApplyPalette( out, indexes ); 1661 } 1662 return true; 1663 case ICN::LOCATORE: 1664 case ICN::LOCATORS: 1665 LoadOriginalICN( id ); 1666 if ( _icnVsSprite[id].size() > 15 ) { 1667 if ( _icnVsSprite[id][12].width() == 47 ) { 1668 Sprite & out = _icnVsSprite[id][12]; 1669 out = Crop( out, 0, 0, out.width() - 1, out.height() ); 1670 } 1671 if ( _icnVsSprite[id][15].width() == 47 ) { 1672 Sprite & out = _icnVsSprite[id][15]; 1673 out = Crop( out, 0, 0, out.width() - 1, out.height() ); 1674 } 1675 } 1676 return true; 1677 case ICN::TOWNBKG2: 1678 LoadOriginalICN( id ); 1679 if ( _icnVsSprite[id].size() == 1 ) { 1680 Sprite & out = _icnVsSprite[id][0]; 1681 // The pixel pixel of the original sprite has a skip value 1682 if ( !out.empty() && out.transform()[0] == 1 ) { 1683 out.transform()[0] = 0; 1684 out.image()[0] = 10; 1685 } 1686 } 1687 return true; 1688 case ICN::HSICONS: 1689 LoadOriginalICN( id ); 1690 if ( _icnVsSprite[id].size() > 7 ) { 1691 Sprite & out = _icnVsSprite[id][7]; 1692 if ( out.width() == 34 && out.height() == 19 ) { 1693 Sprite temp; 1694 std::swap( temp, out ); 1695 1696 out.resize( temp.width() + 1, temp.height() ); 1697 out.reset(); 1698 Copy( temp, 0, 0, out, 1, 0, temp.width(), temp.height() ); 1699 Copy( temp, temp.width() - 1, 10, out, 0, 10, 1, 3 ); 1700 } 1701 } 1702 return true; 1703 case ICN::LISTBOX_EVIL: 1704 CopyICNWithPalette( id, ICN::LISTBOX, PAL::PaletteType::GRAY ); 1705 for ( size_t i = 0; i < _icnVsSprite[id].size(); ++i ) { 1706 ApplyPalette( _icnVsSprite[id][i], 2 ); 1707 } 1708 return true; 1709 case ICN::MONS32: 1710 LoadOriginalICN( id ); 1711 1712 if ( _icnVsSprite[id].size() > 4 ) { // Veteran Pikeman 1713 Sprite & modified = _icnVsSprite[id][4]; 1714 1715 Sprite temp( modified.width(), modified.height() + 1 ); 1716 temp.reset(); 1717 Blit( modified, 0, 0, temp, 0, 1, modified.width(), modified.height() ); 1718 modified = std::move( temp ); 1719 Fill( modified, 7, 0, 4, 1, 36 ); 1720 } 1721 if ( _icnVsSprite[id].size() > 6 ) { // Master Swordsman 1722 Sprite & modified = _icnVsSprite[id][6]; 1723 1724 Sprite temp( modified.width(), modified.height() + 1 ); 1725 temp.reset(); 1726 Blit( modified, 0, 0, temp, 0, 1, modified.width(), modified.height() ); 1727 modified = std::move( temp ); 1728 Fill( modified, 2, 0, 5, 1, 36 ); 1729 } 1730 if ( _icnVsSprite[id].size() > 8 ) { // Champion 1731 Sprite & modified = _icnVsSprite[id][8]; 1732 1733 Sprite temp( modified.width(), modified.height() + 1 ); 1734 temp.reset(); 1735 Blit( modified, 0, 0, temp, 0, 1, modified.width(), modified.height() ); 1736 modified = std::move( temp ); 1737 Fill( modified, 12, 0, 5, 1, 36 ); 1738 } 1739 if ( _icnVsSprite[id].size() > 62 ) { 1740 const Point shadowOffset( -1, 2 ); 1741 for ( size_t i = 0; i < 62; ++i ) { 1742 Sprite & modified = _icnVsSprite[id][i]; 1743 const Point originalOffset( modified.x(), modified.y() ); 1744 Sprite temp = addShadow( modified, Point( -1, 2 ), 2 ); 1745 temp.setPosition( originalOffset.x - 1, originalOffset.y + 2 ); 1746 1747 const Rect area = GetActiveROI( temp, 2 ); 1748 if ( area.x > 0 || area.height != temp.height() ) { 1749 const Point offset( temp.x() - area.x, temp.y() - temp.height() + area.y + area.height ); 1750 modified = Crop( temp, area.x, area.y, area.width, area.height ); 1751 modified.setPosition( offset.x, offset.y ); 1752 } 1753 else { 1754 modified = std::move( temp ); 1755 } 1756 } 1757 } 1758 if ( _icnVsSprite[id].size() > 63 && _icnVsSprite[id][63].width() == 19 && _icnVsSprite[id][63].height() == 37 ) { // Air Elemental 1759 Sprite & modified = _icnVsSprite[id][63]; 1760 modified.image()[19 * 9 + 9] = modified.image()[19 * 5 + 11]; 1761 modified.transform()[19 * 9 + 9] = modified.transform()[19 * 5 + 11]; 1762 } 1763 1764 return true; 1765 case ICN::MONSTER_SWITCH_LEFT_ARROW: 1766 _icnVsSprite[id].resize( 2 ); 1767 for ( uint32_t i = 0; i < 2; ++i ) { 1768 const Sprite & source = GetICN( ICN::RECRUIT, i ); 1769 Sprite & out = _icnVsSprite[id][i]; 1770 out.resize( source.height(), source.width() ); 1771 Transpose( source, out ); 1772 out = Flip( out, false, true ); 1773 out.setPosition( source.y(), source.x() ); 1774 } 1775 return true; 1776 case ICN::MONSTER_SWITCH_RIGHT_ARROW: 1777 _icnVsSprite[id].resize( 2 ); 1778 for ( uint32_t i = 0; i < 2; ++i ) { 1779 const Sprite & source = GetICN( ICN::RECRUIT, i + 2 ); 1780 Sprite & out = _icnVsSprite[id][i]; 1781 out.resize( source.height(), source.width() ); 1782 Transpose( source, out ); 1783 out = Flip( out, false, true ); 1784 out.setPosition( source.y(), source.x() ); 1785 } 1786 return true; 1787 case ICN::SURRENDR: 1788 case ICN::SURRENDE: 1789 LoadOriginalICN( id ); 1790 if ( _icnVsSprite[id].size() >= 4 ) { 1791 if ( id == ICN::SURRENDR ) { 1792 // Fix incorrect font color on good ACCEPT button. 1793 ReplaceColorId( _icnVsSprite[id][0], 28, 56 ); 1794 } 1795 // Fix pressed buttons background. 1796 for ( uint32_t i : { 0, 2 } ) { 1797 Sprite & out = _icnVsSprite[id][i + 1]; 1798 1799 Sprite tmp( out.width(), out.height() ); 1800 tmp.reset(); 1801 Copy( out, 0, 1, tmp, 1, 0, tmp.width() - 1, tmp.height() - 1 ); 1802 CopyTransformLayer( _icnVsSprite[id][i], tmp ); 1803 1804 out.reset(); 1805 Copy( tmp, 1, 0, out, 0, 1, tmp.width() - 1, tmp.height() - 1 ); 1806 } 1807 } 1808 return true; 1809 case ICN::NON_UNIFORM_GOOD_OKAY_BUTTON: 1810 _icnVsSprite[id].resize( 2 ); 1811 _icnVsSprite[id][0] = Crop( GetICN( ICN::CAMPXTRG, 4 ), 6, 0, 96, 25 ); 1812 _icnVsSprite[id][0].setPosition( 0, 0 ); 1813 1814 _icnVsSprite[id][1] = GetICN( ICN::CAMPXTRG, 5 ); 1815 _icnVsSprite[id][1].setPosition( 0, 0 ); 1816 1817 // fix transparent corners 1818 CopyTransformLayer( _icnVsSprite[id][1], _icnVsSprite[id][0] ); 1819 return true; 1820 case ICN::NON_UNIFORM_GOOD_CANCEL_BUTTON: 1821 _icnVsSprite[id].resize( 2 ); 1822 _icnVsSprite[id][0] = Crop( GetICN( ICN::CAMPXTRG, 6 ), 6, 0, 96, 25 ); 1823 _icnVsSprite[id][0].setPosition( 0, 0 ); 1824 1825 _icnVsSprite[id][1] = GetICN( ICN::CAMPXTRG, 7 ); 1826 _icnVsSprite[id][1].setPosition( 0, 0 ); 1827 1828 // fix transparent corners 1829 CopyTransformLayer( _icnVsSprite[id][1], _icnVsSprite[id][0] ); 1830 return true; 1831 case ICN::NON_UNIFORM_GOOD_RESTART_BUTTON: 1832 _icnVsSprite[id].resize( 2 ); 1833 _icnVsSprite[id][0] = Crop( GetICN( ICN::CAMPXTRG, 2 ), 6, 0, 108, 25 ); 1834 _icnVsSprite[id][0].setPosition( 0, 0 ); 1835 1836 _icnVsSprite[id][1] = GetICN( ICN::CAMPXTRG, 3 ); 1837 _icnVsSprite[id][1].setPosition( 0, 0 ); 1838 1839 // fix transparent corners 1840 CopyTransformLayer( _icnVsSprite[id][1], _icnVsSprite[id][0] ); 1841 return true; 1842 case ICN::NON_UNIFORM_EVIL_OKAY_BUTTON: 1843 _icnVsSprite[id].resize( 2 ); 1844 _icnVsSprite[id][0] = Crop( GetICN( ICN::CAMPXTRE, 4 ), 4, 0, 96, 25 ); 1845 _icnVsSprite[id][0].setPosition( 0, 0 ); 1846 1847 _icnVsSprite[id][1] = GetICN( ICN::CAMPXTRE, 5 ); 1848 _icnVsSprite[id][1].setPosition( 0, 0 ); 1849 1850 // fix transparent corners 1851 CopyTransformLayer( _icnVsSprite[id][1], _icnVsSprite[id][0] ); 1852 return true; 1853 case ICN::NON_UNIFORM_EVIL_CANCEL_BUTTON: 1854 _icnVsSprite[id].resize( 2 ); 1855 _icnVsSprite[id][0] = Crop( GetICN( ICN::CAMPXTRE, 6 ), 4, 0, 96, 25 ); 1856 _icnVsSprite[id][0].setPosition( 0, 0 ); 1857 1858 _icnVsSprite[id][1] = GetICN( ICN::CAMPXTRE, 7 ); 1859 _icnVsSprite[id][1].setPosition( 0, 0 ); 1860 1861 // fix transparent corners 1862 CopyTransformLayer( _icnVsSprite[id][1], _icnVsSprite[id][0] ); 1863 return true; 1864 case ICN::NON_UNIFORM_EVIL_RESTART_BUTTON: 1865 _icnVsSprite[id].resize( 2 ); 1866 _icnVsSprite[id][0] = Crop( GetICN( ICN::CAMPXTRE, 2 ), 4, 0, 108, 25 ); 1867 _icnVsSprite[id][0].setPosition( 0, 0 ); 1868 1869 _icnVsSprite[id][1] = GetICN( ICN::CAMPXTRE, 3 ); 1870 _icnVsSprite[id][1].setPosition( 0, 0 ); 1871 1872 // fix transparent corners 1873 CopyTransformLayer( _icnVsSprite[id][1], _icnVsSprite[id][0] ); 1874 return true; 1875 case ICN::UNIFORM_GOOD_MAX_BUTTON: { 1876 _icnVsSprite[id].resize( 2 ); 1877 1878 // Generate background 1879 Image background( 60, 25 ); 1880 Copy( GetICN( ICN::SYSTEM, 12 ), 0, 0, background, 0, 0, 53, 25 ); 1881 Copy( GetICN( ICN::SYSTEM, 12 ), 89, 0, background, 53, 0, 7, 25 ); 1882 1883 // Released button 1884 Image temp( 60, 25 ); 1885 Copy( GetICN( ICN::SYSTEM, 11 ), 0, 0, temp, 0, 0, 53, 25 ); 1886 Copy( GetICN( ICN::SYSTEM, 11 ), 89, 0, temp, 53, 0, 7, 25 ); 1887 Copy( GetICN( ICN::RECRUIT, 4 ), 9, 2, temp, 4, 2, 52, 19 ); 1888 1889 _icnVsSprite[id][0] = background; 1890 Blit( temp, _icnVsSprite[id][0] ); 1891 _icnVsSprite[id][0].setPosition( 0, 0 ); 1892 1893 // Pressed button 1894 _icnVsSprite[id][1] = background; 1895 Copy( GetICN( ICN::RECRUIT, 5 ), 9, 2, _icnVsSprite[id][1], 3, 2, 53, 19 ); 1896 1897 return true; 1898 } 1899 case ICN::UNIFORM_GOOD_MIN_BUTTON: { 1900 _icnVsSprite[id].resize( 2 ); 1901 1902 // Generate background 1903 Image background( 60, 25 ); 1904 Copy( GetICN( ICN::SYSTEM, 12 ), 0, 0, background, 0, 0, 53, 25 ); 1905 Copy( GetICN( ICN::SYSTEM, 12 ), 89, 0, background, 53, 0, 7, 25 ); 1906 1907 // Released button 1908 Image temp( 60, 25 ); 1909 Copy( GetICN( ICN::SYSTEM, 11 ), 0, 0, temp, 0, 0, 53, 25 ); 1910 Copy( GetICN( ICN::SYSTEM, 11 ), 89, 0, temp, 53, 0, 7, 25 ); 1911 Copy( GetICN( ICN::RECRUIT, 4 ), 9, 2, temp, 4, 2, 21, 19 ); // letter 'M' 1912 Copy( GetICN( ICN::APANEL, 4 ), 23, 21, temp, 28, 5, 8, 14 ); // letter 'I' 1913 Copy( GetICN( ICN::APANEL, 4 ), 31, 21, temp, 39, 5, 17, 14 ); // letter 'N' 1914 1915 _icnVsSprite[id][0] = background; 1916 Blit( temp, _icnVsSprite[id][0] ); 1917 _icnVsSprite[id][0].setPosition( 0, 0 ); 1918 1919 // Pressed button 1920 _icnVsSprite[id][1] = background; 1921 Copy( GetICN( ICN::RECRUIT, 5 ), 9, 3, _icnVsSprite[id][1], 3, 3, 19, 17 ); // letter 'M' 1922 Copy( GetICN( ICN::APANEL, 5 ), 21, 22, _icnVsSprite[id][1], 25, 6, 8, 14 ); // letter 'I' 1923 Copy( GetICN( ICN::APANEL, 5 ), 30, 21, _icnVsSprite[id][1], 37, 5, 17, 15 ); // letter 'N' 1924 1925 return true; 1926 } 1927 case ICN::UNIFORM_EVIL_MAX_BUTTON: { 1928 _icnVsSprite[id].resize( 2 ); 1929 1930 // Generate background 1931 Image background( 60, 25 ); 1932 Copy( GetICN( ICN::SYSTEME, 12 ), 0, 0, background, 0, 0, 53, 25 ); 1933 Copy( GetICN( ICN::SYSTEME, 12 ), 89, 0, background, 53, 0, 7, 25 ); 1934 1935 // Released button 1936 Image temp( 60, 25 ); 1937 Copy( GetICN( ICN::SYSTEME, 11 ), 0, 0, temp, 0, 0, 53, 25 ); 1938 Copy( GetICN( ICN::SYSTEME, 11 ), 89, 0, temp, 53, 0, 7, 25 ); 1939 Copy( GetICN( ICN::CPANELE, 0 ), 46, 28, temp, 6, 5, 19, 14 ); // letter 'M' 1940 Copy( GetICN( ICN::CSPANBTE, 0 ), 49, 5, temp, 25, 5, 13, 14 ); // letter 'A' 1941 Copy( GetICN( ICN::CSPANBTE, 0 ), 62, 10, temp, 38, 10, 2, 9 ); // rest of letter 'A' 1942 Copy( GetICN( ICN::LGNDXTRE, 4 ), 28, 5, temp, 41, 5, 15, 14 ); // letter 'X' 1943 1944 _icnVsSprite[id][0] = background; 1945 Blit( temp, _icnVsSprite[id][0] ); 1946 _icnVsSprite[id][0].setPosition( 0, 0 ); 1947 1948 // Pressed button 1949 _icnVsSprite[id][1] = background; 1950 Copy( GetICN( ICN::CPANELE, 1 ), 45, 29, _icnVsSprite[id][1], 4, 6, 19, 14 ); // letter 'M' 1951 Copy( GetICN( ICN::CSPANBTE, 1 ), 49, 6, _icnVsSprite[id][1], 23, 6, 12, 14 ); // letter 'A' 1952 Copy( GetICN( ICN::CSPANBTE, 1 ), 61, 11, _icnVsSprite[id][1], 35, 11, 3, 9 ); // rest of letter 'A' 1953 Copy( GetICN( ICN::LGNDXTRE, 5 ), 26, 4, _icnVsSprite[id][1], 38, 4, 15, 16 ); // letter 'X' 1954 _icnVsSprite[id][1].image()[353] = 21; 1955 _icnVsSprite[id][1].image()[622] = 21; 1956 _icnVsSprite[id][1].image()[964] = 21; 1957 1958 return true; 1959 } 1960 case ICN::UNIFORM_EVIL_MIN_BUTTON: { 1961 _icnVsSprite[id].resize( 2 ); 1962 1963 // Generate background 1964 Image background( 60, 25 ); 1965 Copy( GetICN( ICN::SYSTEME, 12 ), 0, 0, background, 0, 0, 53, 25 ); 1966 Copy( GetICN( ICN::SYSTEME, 12 ), 89, 0, background, 53, 0, 7, 25 ); 1967 1968 // Released button 1969 Image temp( 60, 25 ); 1970 Copy( GetICN( ICN::SYSTEME, 11 ), 0, 0, temp, 0, 0, 53, 25 ); 1971 Copy( GetICN( ICN::SYSTEME, 11 ), 89, 0, temp, 53, 0, 7, 25 ); 1972 Copy( GetICN( ICN::CPANELE, 0 ), 46, 28, temp, 6, 5, 19, 14 ); // letter 'M' 1973 Copy( GetICN( ICN::APANELE, 4 ), 23, 21, temp, 28, 5, 8, 14 ); // letter 'I' 1974 Copy( GetICN( ICN::APANELE, 4 ), 31, 21, temp, 39, 5, 17, 14 ); // letter 'N' 1975 1976 _icnVsSprite[id][0] = background; 1977 Blit( temp, _icnVsSprite[id][0] ); 1978 _icnVsSprite[id][0].setPosition( 0, 0 ); 1979 1980 // Pressed button 1981 _icnVsSprite[id][1] = background; 1982 Copy( GetICN( ICN::CPANELE, 1 ), 45, 29, _icnVsSprite[id][1], 4, 6, 19, 14 ); // letter 'M' 1983 Copy( GetICN( ICN::APANELE, 5 ), 21, 22, _icnVsSprite[id][1], 25, 6, 8, 14 ); // letter 'I' 1984 Copy( GetICN( ICN::APANELE, 5 ), 30, 21, _icnVsSprite[id][1], 37, 5, 17, 15 ); // letter 'N' 1985 _icnVsSprite[id][1].image()[622] = 21; 1986 _icnVsSprite[id][1].image()[964] = 21; 1987 _icnVsSprite[id][1].image()[1162] = 21; 1988 1989 return true; 1990 } 1991 case ICN::WHITE_LARGE_FONT: { 1992 GetICN( ICN::FONT, 0 ); 1993 const std::vector<Sprite> & original = _icnVsSprite[ICN::FONT]; 1994 _icnVsSprite[id].resize( original.size() ); 1995 for ( size_t i = 0; i < _icnVsSprite[id].size(); ++i ) { 1996 const Sprite & in = original[i]; 1997 Sprite & out = _icnVsSprite[id][i]; 1998 out.resize( in.width() * 2, in.height() * 2 ); 1999 Resize( in, out, true ); 2000 out.setPosition( in.x() * 2, in.y() * 2 ); 2001 } 2002 return true; 2003 } 2004 case ICN::SWAP_ARROW_LEFT_TO_RIGHT: 2005 case ICN::SWAP_ARROW_RIGHT_TO_LEFT: { 2006 // Since the original game does not have such resources we could generate it from hero meeting sprite. 2007 const Sprite & original = GetICN( ICN::SWAPWIN, 0 ); 2008 std::vector<Image> input( 4 ); 2009 2010 const int32_t width = 45; 2011 const int32_t height = 20; 2012 2013 for ( Image & image : input ) 2014 image.resize( width, height ); 2015 2016 Copy( original, 295, 270, input[0], 0, 0, width, height ); 2017 Copy( original, 295, 291, input[1], 0, 0, width, height ); 2018 Copy( original, 295, 363, input[2], 0, 0, width, height ); 2019 Copy( original, 295, 384, input[3], 0, 0, width, height ); 2020 2021 input[1] = Flip( input[1], true, false ); 2022 input[3] = Flip( input[3], true, false ); 2023 2024 Image out = ExtractCommonPattern( input ); 2025 2026 // Here are 2 pixels which should be removed. 2027 if ( out.width() == width && out.height() == height ) { 2028 out.image()[40] = 0; 2029 out.transform()[40] = 1; 2030 2031 out.image()[30 + 3 * width] = 0; 2032 out.transform()[30 + 3 * width] = 1; 2033 } 2034 2035 _icnVsSprite[id].resize( 2 ); 2036 _icnVsSprite[id][0] = ( id == ICN::SWAP_ARROW_LEFT_TO_RIGHT ) ? out : Flip( out, true, false ); 2037 2038 _icnVsSprite[id][1] = _icnVsSprite[id][0]; 2039 _icnVsSprite[id][1].setPosition( -1, 1 ); 2040 ApplyPalette( _icnVsSprite[id][1], 4 ); 2041 2042 return true; 2043 } 2044 case ICN::HEROES: 2045 LoadOriginalICN( id ); 2046 if ( !_icnVsSprite[id].empty() ) { 2047 // This is the main menu image which shouldn't have any transform layer. 2048 _icnVsSprite[id][0]._disableTransformLayer(); 2049 } 2050 return true; 2051 case ICN::TOWNBKG3: 2052 // Warlock town background image contains 'empty' pixels leading to appear them as black. 2053 LoadOriginalICN( id ); 2054 if ( !_icnVsSprite[id].empty() ) { 2055 Sprite & original = _icnVsSprite[id][0]; 2056 if ( original.width() == 640 && original.height() == 256 ) { 2057 replaceTranformPixel( original, 51945, 17 ); 2058 replaceTranformPixel( original, 61828, 25 ); 2059 replaceTranformPixel( original, 64918, 164 ); 2060 replaceTranformPixel( original, 77685, 18 ); 2061 replaceTranformPixel( original, 84618, 19 ); 2062 } 2063 } 2064 return true; 2065 case ICN::PORT0091: 2066 // Barbarian captain has one bad pixel. 2067 LoadOriginalICN( id ); 2068 if ( !_icnVsSprite[id].empty() ) { 2069 Sprite & original = _icnVsSprite[id][0]; 2070 if ( original.width() == 101 && original.height() == 93 ) { 2071 replaceTranformPixel( original, 9084, 77 ); 2072 } 2073 } 2074 return true; 2075 case ICN::PORT0090: 2076 // Knight captain has multiple bad pixels. 2077 LoadOriginalICN( id ); 2078 if ( !_icnVsSprite[id].empty() ) { 2079 Sprite & original = _icnVsSprite[id][0]; 2080 if ( original.width() == 101 && original.height() == 93 ) { 2081 replaceTranformPixel( original, 2314, 70 ); 2082 replaceTranformPixel( original, 5160, 71 ); 2083 replaceTranformPixel( original, 5827, 18 ); 2084 replaceTranformPixel( original, 7474, 167 ); 2085 } 2086 } 2087 return true; 2088 case ICN::CSTLWZRD: 2089 LoadOriginalICN( id ); 2090 if ( _icnVsSprite[id].size() >= 8 ) { 2091 // Statue image has bad pixels. 2092 Sprite & original = _icnVsSprite[id][7]; 2093 if ( original.width() == 135 && original.height() == 57 ) { 2094 replaceTranformPixel( original, 3687, 50 ); 2095 replaceTranformPixel( original, 5159, 108 ); 2096 replaceTranformPixel( original, 5294, 108 ); 2097 } 2098 } 2099 if ( _icnVsSprite[id].size() >= 24 ) { 2100 // Mage tower image has a bad pixel. 2101 Sprite & original = _icnVsSprite[id][23]; 2102 if ( original.width() == 135 && original.height() == 57 ) { 2103 replaceTranformPixel( original, 4333, 23 ); 2104 } 2105 } 2106 if ( _icnVsSprite[id].size() >= 29 ) { 2107 // Mage tower image has a bad pixel. 2108 Sprite & original = _icnVsSprite[id][28]; 2109 if ( original.width() == 135 && original.height() == 57 ) { 2110 replaceTranformPixel( original, 4333, 23 ); 2111 } 2112 } 2113 return true; 2114 case ICN::CSTLCAPK: 2115 // Knight captain has a bad pixel. 2116 LoadOriginalICN( id ); 2117 if ( _icnVsSprite[id].size() >= 2 ) { 2118 Sprite & original = _icnVsSprite[id][1]; 2119 if ( original.width() == 84 && original.height() == 81 ) { 2120 replaceTranformPixel( original, 4934, 18 ); 2121 } 2122 } 2123 return true; 2124 case ICN::CSTLCAPW: 2125 // Warlock captain quarters have bad pixels. 2126 LoadOriginalICN( id ); 2127 if ( !_icnVsSprite[id].empty() ) { 2128 Sprite & original = _icnVsSprite[id][0]; 2129 if ( original.width() == 84 && original.height() == 81 ) { 2130 replaceTranformPixel( original, 1692, 26 ); 2131 replaceTranformPixel( original, 2363, 32 ); 2132 replaceTranformPixel( original, 2606, 21 ); 2133 replaceTranformPixel( original, 2608, 21 ); 2134 } 2135 } 2136 return true; 2137 case ICN::CSTLSORC: 2138 LoadOriginalICN( id ); 2139 if ( _icnVsSprite[id].size() >= 14 ) { 2140 // Rainbow has bad pixels. 2141 Sprite & original = _icnVsSprite[id][13]; 2142 if ( original.width() == 135 && original.height() == 57 ) { 2143 replaceTranformPixel( original, 2047, 160 ); 2144 replaceTranformPixel( original, 2052, 159 ); 2145 replaceTranformPixel( original, 2055, 160 ); 2146 replaceTranformPixel( original, 2060, 67 ); 2147 replaceTranformPixel( original, 2063, 159 ); 2148 replaceTranformPixel( original, 2067, 67 ); 2149 replaceTranformPixel( original, 2184, 67 ); 2150 replaceTranformPixel( original, 2192, 158 ); 2151 replaceTranformPixel( original, 3508, 67 ); 2152 replaceTranformPixel( original, 3641, 67 ); 2153 replaceTranformPixel( original, 3773, 69 ); 2154 replaceTranformPixel( original, 3910, 67 ); 2155 replaceTranformPixel( original, 4039, 69 ); 2156 replaceTranformPixel( original, 4041, 67 ); 2157 replaceTranformPixel( original, 4172, 67 ); 2158 replaceTranformPixel( original, 4578, 69 ); 2159 } 2160 } 2161 if ( _icnVsSprite[id].size() >= 25 ) { 2162 // Red tower has bad pixels. 2163 Sprite & original = _icnVsSprite[id][24]; 2164 if ( original.width() == 135 && original.height() == 57 ) { 2165 replaceTranformPixel( original, 2830, 165 ); 2166 replaceTranformPixel( original, 3101, 165 ); 2167 replaceTranformPixel( original, 3221, 69 ); 2168 } 2169 } 2170 return true; 2171 case ICN::CURSOR_ADVENTURE_MAP: { 2172 // Create needed numbers 2173 const std::vector<Point> twoPoints = { { 2, 1 }, { 3, 1 }, { 1, 2 }, { 4, 2 }, { 3, 3 }, { 2, 4 }, { 1, 5 }, { 2, 5 }, { 3, 5 }, { 4, 5 } }; 2174 const std::vector<Point> threePoints = { { 1, 1 }, { 2, 1 }, { 3, 1 }, { 4, 2 }, { 1, 3 }, { 2, 3 }, { 3, 3 }, { 4, 4 }, { 1, 5 }, { 2, 5 }, { 3, 5 } }; 2175 const std::vector<Point> fourPoints = { { 1, 1 }, { 3, 1 }, { 1, 2 }, { 3, 2 }, { 1, 3 }, { 2, 3 }, { 3, 3 }, { 4, 3 }, { 3, 4 }, { 3, 5 } }; 2176 const std::vector<Point> fivePoints 2177 = { { 1, 1 }, { 2, 1 }, { 3, 1 }, { 4, 1 }, { 1, 2 }, { 1, 3 }, { 2, 3 }, { 3, 3 }, { 4, 4 }, { 1, 5 }, { 2, 5 }, { 3, 5 } }; 2178 const std::vector<Point> sixPoints = { { 2, 1 }, { 3, 1 }, { 1, 2 }, { 1, 3 }, { 2, 3 }, { 3, 3 }, { 1, 4 }, { 4, 4 }, { 2, 5 }, { 3, 5 } }; 2179 const std::vector<Point> sevenPoints = { { 1, 1 }, { 2, 1 }, { 3, 1 }, { 4, 1 }, { 4, 2 }, { 3, 3 }, { 2, 4 }, { 2, 5 } }; 2180 const std::vector<Point> plusPoints = { { 2, 1 }, { 1, 2 }, { 2, 2 }, { 3, 2 }, { 2, 3 } }; 2181 2182 std::vector<Image> digits( 7 ); 2183 digits[0] = createDigit( 6, 7, twoPoints ); 2184 digits[1] = createDigit( 6, 7, threePoints ); 2185 digits[2] = createDigit( 6, 7, fourPoints ); 2186 digits[3] = createDigit( 6, 7, fivePoints ); 2187 digits[4] = createDigit( 6, 7, sixPoints ); 2188 digits[5] = createDigit( 6, 7, sevenPoints ); 2189 digits[6] = addDigit( digits[5], createDigit( 5, 5, plusPoints ), Point( -1, -1 ) ); 2190 2191 _icnVsSprite[id].reserve( 7 * 8 ); 2192 2193 populateCursorIcons( _icnVsSprite[id], GetICN( ICN::ADVMCO, 4 ), digits, Point( -2, 1 ) ); 2194 populateCursorIcons( _icnVsSprite[id], GetICN( ICN::ADVMCO, 5 ), digits, Point( 1, 1 ) ); 2195 populateCursorIcons( _icnVsSprite[id], GetICN( ICN::ADVMCO, 6 ), digits, Point( 0, 1 ) ); 2196 populateCursorIcons( _icnVsSprite[id], GetICN( ICN::ADVMCO, 7 ), digits, Point( -2, 1 ) ); 2197 populateCursorIcons( _icnVsSprite[id], GetICN( ICN::ADVMCO, 8 ), digits, Point( 1, 1 ) ); 2198 populateCursorIcons( _icnVsSprite[id], GetICN( ICN::ADVMCO, 9 ), digits, Point( -6, 1 ) ); 2199 populateCursorIcons( _icnVsSprite[id], GetICN( ICN::ADVMCO, 28 ), digits, Point( 0, 1 ) ); 2200 2201 return true; 2202 } 2203 case ICN::DISMISS_HERO_DISABLED_BUTTON: 2204 case ICN::NEW_CAMPAIGN_DISABLED_BUTTON: 2205 case ICN::MAX_DISABLED_BUTTON: { 2206 _icnVsSprite[id].resize( 1 ); 2207 Sprite & output = _icnVsSprite[id][0]; 2208 2209 int buttonIcnId = ICN::UNKNOWN; 2210 uint32_t startIcnId = 0; 2211 2212 if ( id == ICN::DISMISS_HERO_DISABLED_BUTTON ) { 2213 buttonIcnId = ICN::HSBTNS; 2214 startIcnId = 0; 2215 } 2216 else if ( id == ICN::NEW_CAMPAIGN_DISABLED_BUTTON ) { 2217 buttonIcnId = ICN::BTNNEWGM; 2218 startIcnId = 2; 2219 } 2220 else if ( id == ICN::MAX_DISABLED_BUTTON ) { 2221 buttonIcnId = ICN::RECRUIT; 2222 startIcnId = 4; 2223 } 2224 2225 assert( buttonIcnId != ICN::UNKNOWN ); // Did you add a new disabled button and forget to add the condition above? 2226 2227 const Sprite & released = GetICN( buttonIcnId, startIcnId ); 2228 const Sprite & pressed = GetICN( buttonIcnId, startIcnId + 1 ); 2229 output = released; 2230 2231 ApplyPalette( output, PAL::GetPalette( PAL::PaletteType::DARKENING ) ); 2232 2233 Image common = ExtractCommonPattern( { released, pressed } ); 2234 common = FilterOnePixelNoise( common ); 2235 common = FilterOnePixelNoise( common ); 2236 common = FilterOnePixelNoise( common ); 2237 2238 Blit( common, output ); 2239 return true; 2240 } 2241 case ICN::KNIGHT_CASTLE_RIGHT_FARM: { 2242 _icnVsSprite[id].resize( 1 ); 2243 Sprite & output = _icnVsSprite[id][0]; 2244 output = GetICN( ICN::TWNKWEL2, 0 ); 2245 2246 ApplyPalette( output, 28, 21, output, 28, 21, 39, 1, 8 ); 2247 ApplyPalette( output, 0, 22, output, 0, 22, 69, 1, 8 ); 2248 ApplyPalette( output, 0, 23, output, 0, 23, 53, 1, 8 ); 2249 ApplyPalette( output, 0, 24, output, 0, 24, 54, 1, 8 ); 2250 ApplyPalette( output, 0, 25, output, 0, 25, 62, 1, 8 ); 2251 return true; 2252 } 2253 case ICN::KNIGHT_CASTLE_LEFT_FARM: 2254 _icnVsSprite[id].resize( 1 ); 2255 h2d::readImage( "knight_castle_left_farm.image", _icnVsSprite[id][0] ); 2256 return true; 2257 case ICN::BARBARIAN_CASTLE_CAPTAIN_QUARTERS_LEFT_SIDE: 2258 _icnVsSprite[id].resize( 1 ); 2259 h2d::readImage( "barbarian_castle_captain_quarter_left_side.image", _icnVsSprite[id][0] ); 2260 return true; 2261 case ICN::NECROMANCER_CASTLE_STANDALONE_CAPTAIN_QUARTERS: { 2262 _icnVsSprite[id].resize( 1 ); 2263 Sprite & output = _icnVsSprite[id][0]; 2264 const Sprite & original = GetICN( ICN::TWNNCAPT, 0 ); 2265 2266 output = Crop( original, 21, 0, original.width() - 21, original.height() ); 2267 output.setPosition( original.x() + 21, original.y() ); 2268 2269 for ( int32_t y = 47; y < output.height(); ++y ) { 2270 SetTransformPixel( output, 0, y, 1 ); 2271 } 2272 2273 const Sprite & castle = GetICN( ICN::TWNNCSTL, 0 ); 2274 Copy( castle, 402, 123, output, 1, 56, 2, 11 ); 2275 2276 return true; 2277 } 2278 case ICN::NECROMANCER_CASTLE_CAPTAIN_QUARTERS_BRIDGE: { 2279 _icnVsSprite[id].resize( 1 ); 2280 Sprite & output = _icnVsSprite[id][0]; 2281 const Sprite & original = GetICN( ICN::TWNNCAPT, 0 ); 2282 2283 output = Crop( original, 0, 0, 23, original.height() ); 2284 output.setPosition( original.x(), original.y() ); 2285 2286 return true; 2287 } 2288 case ICN::ESCROLL: 2289 LoadOriginalICN( id ); 2290 if ( _icnVsSprite[id].size() > 4 ) { 2291 // fix missing black border on the right side of the "up" button 2292 Sprite & out = _icnVsSprite[id][4]; 2293 if ( out.width() == 16 && out.height() == 16 ) { 2294 Copy( out, 0, 0, out, 15, 0, 1, 16 ); 2295 } 2296 } 2297 return true; 2298 case ICN::MAP_TYPE_ICON: { 2299 // TODO: add a new icon for the Resurrection add-on map type. 2300 _icnVsSprite[id].resize( 2 ); 2301 for ( Sprite & icon : _icnVsSprite[id] ) { 2302 icon.resize( 17, 17 ); 2303 icon.fill( 0 ); 2304 } 2305 2306 const Sprite & successionWarsIcon = GetICN( ICN::ARTFX, 6 ); 2307 const Sprite & priceOfLoyaltyIcon = GetICN( ICN::ARTFX, 90 ); 2308 2309 if ( !successionWarsIcon.empty() ) { 2310 Resize( successionWarsIcon, 0, 0, successionWarsIcon.width(), successionWarsIcon.height(), _icnVsSprite[id][0], 1, 1, 15, 15 ); 2311 } 2312 2313 if ( !priceOfLoyaltyIcon.empty() ) { 2314 Resize( priceOfLoyaltyIcon, 0, 0, priceOfLoyaltyIcon.width(), priceOfLoyaltyIcon.height(), _icnVsSprite[id][1], 1, 1, 15, 15 ); 2315 } 2316 2317 return true; 2318 } 2319 case ICN::TWNWWEL2: { 2320 LoadOriginalICN( id ); 2321 if ( _icnVsSprite[id].size() == 7 ) { 2322 if ( _icnVsSprite[id][0].width() == 122 && _icnVsSprite[id][0].height() == 226 ) { 2323 FillTransform( _icnVsSprite[id][0], 0, 57, 56, 62, 1 ); 2324 } 2325 2326 for ( size_t i = 1; i < 7; i++ ) { 2327 Sprite & original = _icnVsSprite[id][i]; 2328 if ( original.width() == 121 && original.height() == 151 ) { 2329 FillTransform( original, 0, 0, 64, 39, 1 ); 2330 } 2331 } 2332 } 2333 return true; 2334 } 2335 case ICN::TWNWCAPT: { 2336 LoadOriginalICN( id ); 2337 if ( !_icnVsSprite[id].empty() ) { 2338 Sprite & original = _icnVsSprite[id][0]; 2339 if ( original.width() == 118 && original.height() ) { 2340 // Remove shadow from left side. 2341 FillTransform( original, 85, 84, 33, 26, 1 ); 2342 2343 // Remove extra terrain at the bottom. 2344 FillTransform( original, 0, 114, 40, 4, 1 ); 2345 FillTransform( original, 9, 112, 51, 2, 1 ); 2346 FillTransform( original, 35, 110, 47, 2, 1 ); 2347 FillTransform( original, 57, 108, 51, 2, 1 ); 2348 } 2349 } 2350 return true; 2351 } 2352 case ICN::GOOD_ARMY_BUTTON: 2353 case ICN::GOOD_MARKET_BUTTON: { 2354 _icnVsSprite[id].resize( 2 ); 2355 2356 const int releasedIndex = ( id == ICN::GOOD_ARMY_BUTTON ) ? 0 : 4; 2357 _icnVsSprite[id][0] = GetICN( ICN::ADVBTNS, releasedIndex ); 2358 _icnVsSprite[id][1] = GetICN( ICN::ADVBTNS, releasedIndex + 1 ); 2359 AddTransparency( _icnVsSprite[id][0], 36 ); 2360 AddTransparency( _icnVsSprite[id][1], 36 ); 2361 AddTransparency( _icnVsSprite[id][1], 61 ); // remove the extra brown border 2362 2363 return true; 2364 } 2365 case ICN::EVIL_ARMY_BUTTON: 2366 case ICN::EVIL_MARKET_BUTTON: { 2367 _icnVsSprite[id].resize( 2 ); 2368 2369 const int releasedIndex = ( id == ICN::EVIL_ARMY_BUTTON ) ? 0 : 4; 2370 _icnVsSprite[id][0] = GetICN( ICN::ADVEBTNS, releasedIndex ); 2371 AddTransparency( _icnVsSprite[id][0], 36 ); 2372 2373 Sprite pressed = GetICN( ICN::ADVEBTNS, releasedIndex + 1 ); 2374 AddTransparency( pressed, 36 ); 2375 AddTransparency( pressed, 61 ); // remove the extra brown border 2376 2377 _icnVsSprite[id][1] = Sprite( pressed.width(), pressed.height(), pressed.x(), pressed.y() ); 2378 _icnVsSprite[id][1].reset(); 2379 2380 // put back pixels that actually should be black 2381 Fill( _icnVsSprite[id][1], 1, 4, 31, 31, 36 ); 2382 Blit( pressed, _icnVsSprite[id][1] ); 2383 2384 return true; 2385 } 2386 case ICN::SPANBTN: 2387 case ICN::SPANBTNE: 2388 case ICN::CSPANBTN: 2389 case ICN::CSPANBTE: { 2390 LoadOriginalICN( id ); 2391 if ( !_icnVsSprite[id].empty() ) { 2392 // add missing part of the released button state on the left 2393 Sprite & out = _icnVsSprite[id][0]; 2394 2395 Sprite released( out.width() + 1, out.height() ); 2396 released.reset(); 2397 const uint8_t color = id == ICN::SPANBTN || id == ICN::CSPANBTN ? 57 : 32; 2398 DrawLine( released, Point( 0, 3 ), Point( 0, out.height() - 1 ), color ); 2399 Blit( out, released, 1, 0 ); 2400 2401 out = std::move( released ); 2402 } 2403 return true; 2404 } 2405 case ICN::TRADPOSE: { 2406 LoadOriginalICN( id ); 2407 if ( _icnVsSprite[id].size() >= 19 ) { 2408 // fix background for TRADE and EXIT buttons 2409 for ( uint32_t i : { 16, 18 } ) { 2410 Sprite pressed; 2411 std::swap( pressed, _icnVsSprite[id][i] ); 2412 AddTransparency( pressed, 25 ); // remove too dark background 2413 2414 // take background from the empty system button 2415 _icnVsSprite[id][i] = GetICN( ICN::SYSTEME, 12 ); 2416 2417 // put back dark-gray pixels in the middle of the button 2418 Fill( _icnVsSprite[id][i], 5, 5, 86, 17, 25 ); 2419 Blit( pressed, _icnVsSprite[id][i] ); 2420 } 2421 } 2422 return true; 2423 } 2424 case ICN::RECRUIT: { 2425 LoadOriginalICN( id ); 2426 if ( _icnVsSprite[id].size() >= 10 ) { 2427 // fix transparent corners on released OKAY button 2428 CopyTransformLayer( _icnVsSprite[id][9], _icnVsSprite[id][8] ); 2429 } 2430 return true; 2431 } 2432 case ICN::NGEXTRA: { 2433 LoadOriginalICN( id ); 2434 if ( _icnVsSprite[id].size() >= 70 ) { 2435 // fix transparent corners on pressed OKAY and CANCEL buttons 2436 CopyTransformLayer( _icnVsSprite[id][66], _icnVsSprite[id][67] ); 2437 CopyTransformLayer( _icnVsSprite[id][68], _icnVsSprite[id][69] ); 2438 } 2439 return true; 2440 } 2441 case ICN::HSBTNS: { 2442 LoadOriginalICN( id ); 2443 if ( _icnVsSprite[id].size() >= 4 ) { 2444 // extract the EXIT button without background 2445 Image exitReleased = _icnVsSprite[id][2]; 2446 Image exitPressed = _icnVsSprite[id][3]; 2447 2448 // make the border parts around EXIT button transparent 2449 Image exitCommonMask = ExtractCommonPattern( { exitReleased, exitPressed } ); 2450 invertTransparency( exitCommonMask ); 2451 2452 CopyTransformLayer( exitCommonMask, exitReleased ); 2453 CopyTransformLayer( exitCommonMask, exitPressed ); 2454 2455 // fix DISMISS button: get the EXIT button, then slap the text back 2456 Sprite & dismissReleased = _icnVsSprite[id][0]; 2457 2458 Sprite tmpReleased = dismissReleased; 2459 Blit( exitReleased, 0, 0, tmpReleased, 5, 0, 27, 120 ); 2460 Blit( dismissReleased, 9, 4, tmpReleased, 9, 4, 19, 110 ); 2461 2462 dismissReleased = std::move( tmpReleased ); 2463 2464 Sprite & dismissPressed = _icnVsSprite[id][1]; 2465 2466 // start with the released state as well to capture more details 2467 Sprite tmpPressed = dismissReleased; 2468 Blit( exitPressed, 0, 0, tmpPressed, 5, 0, 27, 120 ); 2469 Blit( dismissPressed, 9, 5, tmpPressed, 8, 5, 19, 110 ); 2470 2471 dismissPressed = std::move( tmpPressed ); 2472 } 2473 return true; 2474 } 2475 default: 2476 break; 2477 } 2478 2479 return false; 2480 } 2481 GetMaximumICNIndex(int id)2482 size_t GetMaximumICNIndex( int id ) 2483 { 2484 if ( _icnVsSprite[id].empty() && !LoadModifiedICN( id ) ) { 2485 LoadOriginalICN( id ); 2486 } 2487 2488 return _icnVsSprite[id].size(); 2489 } 2490 GetMaximumTILIndex(int id)2491 size_t GetMaximumTILIndex( int id ) 2492 { 2493 if ( _tilVsImage[id].empty() ) { 2494 _tilVsImage[id].resize( 4 ); // 4 possible sides 2495 2496 const std::vector<uint8_t> & data = ::AGG::ReadChunk( tilFileName[id] ); 2497 if ( data.size() < headerSize ) { 2498 return 0; 2499 } 2500 2501 StreamBuf buffer( data ); 2502 2503 const uint32_t count = buffer.getLE16(); 2504 const uint32_t width = buffer.getLE16(); 2505 const uint32_t height = buffer.getLE16(); 2506 const uint32_t size = width * height; 2507 if ( headerSize + count * size != data.size() ) { 2508 return 0; 2509 } 2510 2511 std::vector<Image> & originalTIL = _tilVsImage[id][0]; 2512 2513 originalTIL.resize( count ); 2514 for ( uint32_t i = 0; i < count; ++i ) { 2515 Image & tilImage = originalTIL[i]; 2516 tilImage.resize( width, height ); 2517 tilImage._disableTransformLayer(); 2518 memcpy( tilImage.image(), data.data() + headerSize + i * size, size ); 2519 std::fill( tilImage.transform(), tilImage.transform() + width * height, 0 ); 2520 } 2521 2522 for ( uint32_t shapeId = 1; shapeId < 4; ++shapeId ) { 2523 std::vector<Image> & currentTIL = _tilVsImage[id][shapeId]; 2524 currentTIL.resize( count ); 2525 2526 const bool horizontalFlip = ( shapeId & 2 ) != 0; 2527 const bool verticalFlip = ( shapeId & 1 ) != 0; 2528 2529 for ( uint32_t i = 0; i < count; ++i ) { 2530 currentTIL[i] = Flip( originalTIL[i], horizontalFlip, verticalFlip ); 2531 } 2532 } 2533 } 2534 2535 return _tilVsImage[id][0].size(); 2536 } 2537 2538 // We have few ICNs which we need to scale like some related to main screen IsScalableICN(int id)2539 bool IsScalableICN( int id ) 2540 { 2541 return id == ICN::HEROES || id == ICN::BTNSHNGL || id == ICN::SHNGANIM; 2542 } 2543 GetScaledICN(int icnId,uint32_t index)2544 const Sprite & GetScaledICN( int icnId, uint32_t index ) 2545 { 2546 const Sprite & originalIcn = _icnVsSprite[icnId][index]; 2547 2548 if ( Display::DEFAULT_WIDTH == Display::instance().width() && Display::DEFAULT_HEIGHT == Display::instance().height() ) { 2549 return originalIcn; 2550 } 2551 2552 if ( _icnVsScaledSprite[icnId].empty() ) { 2553 _icnVsScaledSprite[icnId].resize( _icnVsSprite[icnId].size() ); 2554 } 2555 2556 Sprite & resizedIcn = _icnVsScaledSprite[icnId][index]; 2557 2558 const double scaleFactorX = static_cast<double>( Display::instance().width() ) / Display::DEFAULT_WIDTH; 2559 const double scaleFactorY = static_cast<double>( Display::instance().height() ) / Display::DEFAULT_HEIGHT; 2560 2561 const int32_t resizedWidth = static_cast<int32_t>( originalIcn.width() * scaleFactorX + 0.5 ); 2562 const int32_t resizedHeight = static_cast<int32_t>( originalIcn.height() * scaleFactorY + 0.5 ); 2563 // Resize only if needed 2564 if ( resizedIcn.width() != resizedWidth || resizedIcn.height() != resizedHeight ) { 2565 resizedIcn.resize( resizedWidth, resizedHeight ); 2566 resizedIcn.setPosition( static_cast<int32_t>( originalIcn.x() * scaleFactorX + 0.5 ), static_cast<int32_t>( originalIcn.y() * scaleFactorY + 0.5 ) ); 2567 Resize( originalIcn, resizedIcn, false ); 2568 } 2569 2570 return resizedIcn; 2571 } 2572 GetICN(int icnId,uint32_t index)2573 const Sprite & GetICN( int icnId, uint32_t index ) 2574 { 2575 if ( !IsValidICNId( icnId ) ) { 2576 return errorImage; 2577 } 2578 2579 if ( index >= GetMaximumICNIndex( icnId ) ) { 2580 return errorImage; 2581 } 2582 2583 if ( IsScalableICN( icnId ) ) { 2584 return GetScaledICN( icnId, index ); 2585 } 2586 2587 return _icnVsSprite[icnId][index]; 2588 } 2589 GetICNCount(int icnId)2590 uint32_t GetICNCount( int icnId ) 2591 { 2592 if ( !IsValidICNId( icnId ) ) { 2593 return 0; 2594 } 2595 2596 return static_cast<uint32_t>( GetMaximumICNIndex( icnId ) ); 2597 } 2598 GetTIL(int tilId,uint32_t index,uint32_t shapeId)2599 const Image & GetTIL( int tilId, uint32_t index, uint32_t shapeId ) 2600 { 2601 if ( shapeId > 3 ) { 2602 return errorImage; 2603 } 2604 2605 if ( !IsValidTILId( tilId ) ) { 2606 return errorImage; 2607 } 2608 2609 const size_t maxTILIndex = GetMaximumTILIndex( tilId ); 2610 if ( index >= maxTILIndex ) { 2611 return errorImage; 2612 } 2613 2614 return _tilVsImage[tilId][shapeId][index]; 2615 } 2616 GetLetter(uint32_t character,uint32_t fontType)2617 const Sprite & GetLetter( uint32_t character, uint32_t fontType ) 2618 { 2619 if ( character < 0x21 ) { 2620 return errorImage; 2621 } 2622 2623 // TODO: correct naming and standartise the code 2624 switch ( fontType ) { 2625 case Font::GRAY_BIG: 2626 return GetICN( ICN::GRAY_FONT, character - 0x20 ); 2627 case Font::GRAY_SMALL: 2628 return GetICN( ICN::GRAY_SMALL_FONT, character - 0x20 ); 2629 case Font::YELLOW_BIG: 2630 return GetICN( ICN::YELLOW_FONT, character - 0x20 ); 2631 case Font::YELLOW_SMALL: 2632 return GetICN( ICN::YELLOW_SMALLFONT, character - 0x20 ); 2633 case Font::BIG: 2634 return GetICN( ICN::FONT, character - 0x20 ); 2635 case Font::SMALL: 2636 return GetICN( ICN::SMALFONT, character - 0x20 ); 2637 case Font::WHITE_LARGE: 2638 return GetICN( ICN::WHITE_LARGE_FONT, character - 0x20 ); 2639 default: 2640 break; 2641 } 2642 2643 return GetICN( ICN::SMALFONT, character - 0x20 ); 2644 } 2645 ASCIILastSupportedCharacter(const uint32_t fontType)2646 uint32_t ASCIILastSupportedCharacter( const uint32_t fontType ) 2647 { 2648 switch ( fontType ) { 2649 case Font::BIG: 2650 case Font::GRAY_BIG: 2651 case Font::YELLOW_BIG: 2652 case Font::WHITE_LARGE: 2653 return static_cast<uint32_t>( GetMaximumICNIndex( ICN::FONT ) ) + 0x20 - 1; 2654 case Font::SMALL: 2655 case Font::GRAY_SMALL: 2656 case Font::YELLOW_SMALL: 2657 return static_cast<uint32_t>( GetMaximumICNIndex( ICN::SMALFONT ) ) + 0x20 - 1; 2658 default: 2659 return 0; 2660 } 2661 } 2662 GetAbsoluteICNHeight(int icnId)2663 int32_t GetAbsoluteICNHeight( int icnId ) 2664 { 2665 const uint32_t frameCount = GetICNCount( icnId ); 2666 if ( frameCount == 0 ) { 2667 return 0; 2668 } 2669 2670 int32_t height = 0; 2671 for ( uint32_t i = 0; i < frameCount; ++i ) { 2672 const int32_t offset = -GetICN( icnId, i ).y(); 2673 if ( offset > height ) { 2674 height = offset; 2675 } 2676 } 2677 2678 return height; 2679 } 2680 getCharacterLimit(const FontSize fontSize)2681 uint32_t getCharacterLimit( const FontSize fontSize ) 2682 { 2683 switch ( fontSize ) { 2684 case FontSize::SMALL: 2685 return static_cast<uint32_t>( GetMaximumICNIndex( ICN::SMALFONT ) ) + 0x20 - 1; 2686 case FontSize::NORMAL: 2687 case FontSize::LARGE: 2688 return static_cast<uint32_t>( GetMaximumICNIndex( ICN::FONT ) ) + 0x20 - 1; 2689 default: 2690 assert( 0 ); // Did you add a new font size? Please add implementation. 2691 } 2692 2693 return 0; 2694 } 2695 getChar(const uint8_t character,const FontType & fontType)2696 const Sprite & getChar( const uint8_t character, const FontType & fontType ) 2697 { 2698 if ( character < 0x21 ) { 2699 return errorImage; 2700 } 2701 2702 switch ( fontType.size ) { 2703 case FontSize::SMALL: 2704 switch ( fontType.color ) { 2705 case FontColor::WHITE: 2706 return GetICN( ICN::SMALFONT, character - 0x20 ); 2707 case FontColor::GRAY: 2708 return GetICN( ICN::GRAY_SMALL_FONT, character - 0x20 ); 2709 case FontColor::YELLOW: 2710 return GetICN( ICN::YELLOW_SMALLFONT, character - 0x20 ); 2711 default: 2712 break; 2713 } 2714 break; 2715 case FontSize::NORMAL: 2716 switch ( fontType.color ) { 2717 case FontColor::WHITE: 2718 return GetICN( ICN::FONT, character - 0x20 ); 2719 case FontColor::GRAY: 2720 return GetICN( ICN::GRAY_FONT, character - 0x20 ); 2721 case FontColor::YELLOW: 2722 return GetICN( ICN::YELLOW_FONT, character - 0x20 ); 2723 default: 2724 break; 2725 } 2726 break; 2727 case FontSize::LARGE: 2728 switch ( fontType.color ) { 2729 case FontColor::WHITE: 2730 return GetICN( ICN::WHITE_LARGE_FONT, character - 0x20 ); 2731 default: 2732 break; 2733 } 2734 break; 2735 default: 2736 break; 2737 } 2738 2739 assert( 0 ); // Did you add a new font size? Please add implementation. 2740 2741 return errorImage; 2742 } 2743 updateAlphabet(const SupportedLanguage language,const bool loadOriginalAlphabet)2744 void updateAlphabet( const SupportedLanguage language, const bool loadOriginalAlphabet ) 2745 { 2746 if ( loadOriginalAlphabet || !isAlphabetSupported( language ) ) { 2747 alphabetPreserver.restore(); 2748 } 2749 else { 2750 alphabetPreserver.preserve(); 2751 generateAlphabet( language ); 2752 } 2753 } 2754 isAlphabetSupported(const SupportedLanguage language)2755 bool isAlphabetSupported( const SupportedLanguage language ) 2756 { 2757 switch ( language ) { 2758 case SupportedLanguage::Polish: 2759 case SupportedLanguage::German: 2760 case SupportedLanguage::French: 2761 case SupportedLanguage::Russian: 2762 return true; 2763 default: 2764 break; 2765 } 2766 2767 return false; 2768 } 2769 } 2770 } 2771