1 /***************************************************************************
2 * Copyright (C) 2009 by Andrey Afletdinov <fheroes2@gmail.com> *
3 * *
4 * Part of the Free Heroes2 Engine: *
5 * http://sourceforge.net/projects/fheroes2 *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the *
19 * Free Software Foundation, Inc., *
20 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21 ***************************************************************************/
22
23 #include "agg_image.h"
24 #include "bin_info.h"
25 #include "cursor.h"
26 #include "dialog.h"
27 #include "game.h"
28 #include "icn.h"
29 #include "kingdom.h"
30 #include "monster.h"
31 #include "payment.h"
32 #include "settings.h"
33 #include "text.h"
34 #include "tools.h"
35 #include "translations.h"
36 #include "world.h"
37
38 #include <cassert>
39
RedrawCurrentInfo(const fheroes2::Point & pos,u32 result,const payment_t & paymentMonster,const payment_t & paymentCosts,const Funds & funds,const std::string & label)40 void RedrawCurrentInfo( const fheroes2::Point & pos, u32 result, const payment_t & paymentMonster, const payment_t & paymentCosts, const Funds & funds,
41 const std::string & label )
42 {
43 Text text;
44
45 text.Set( std::to_string( result ), Font::BIG );
46 text.Blit( pos.x + 167 - text.w() / 2, pos.y + 161 );
47 const std::string sgold = std::to_string( paymentCosts.gold ) + " " + "(" + std::to_string( funds.gold - paymentCosts.gold ) + ")";
48 int rsext = paymentMonster.GetValidItems() & ~Resource::GOLD;
49
50 if ( rsext ) {
51 text.Set( sgold, Font::SMALL );
52 text.Blit( pos.x + 133 - text.w() / 2, pos.y + 228 );
53
54 text.Set( std::to_string( paymentCosts.Get( rsext ) ) + " " + "(" + std::to_string( funds.Get( rsext ) - paymentCosts.Get( rsext ) ) + ")", Font::SMALL );
55 text.Blit( pos.x + 195 - text.w() / 2, pos.y + 228 );
56 }
57 else {
58 text.Set( sgold, Font::SMALL );
59 text.Blit( pos.x + 160 - text.w() / 2, pos.y + 228 );
60 }
61
62 text.Set( label, Font::SMALL );
63 text.Blit( pos.x + 167 - text.w() / 2, pos.y + 180 );
64 }
65
RedrawResourceInfo(const fheroes2::Image & sres,const fheroes2::Point & pos,s32 value,s32 px1,s32 py1,s32 px2,s32 py2)66 void RedrawResourceInfo( const fheroes2::Image & sres, const fheroes2::Point & pos, s32 value, s32 px1, s32 py1, s32 px2, s32 py2 )
67 {
68 fheroes2::Point dst_pt( pos.x + px1, pos.y + py1 );
69 fheroes2::Blit( sres, fheroes2::Display::instance(), dst_pt.x, dst_pt.y );
70
71 const Text text( std::to_string( value ), Font::SMALL );
72 dst_pt.x = pos.x + px2 - text.w() / 2;
73 dst_pt.y = pos.y + py2;
74 text.Blit( dst_pt.x, dst_pt.y );
75 }
76
RedrawMonsterInfo(const fheroes2::Rect & pos,const Monster & monster,u32 available,bool showTotalSum)77 void RedrawMonsterInfo( const fheroes2::Rect & pos, const Monster & monster, u32 available, bool showTotalSum )
78 {
79 fheroes2::Display & display = fheroes2::Display::instance();
80 const payment_t paymentMonster = monster.GetCost();
81 const bool extres = 2 == paymentMonster.GetValidItemsCount();
82
83 // text recruit monster
84 std::string str = _( "Recruit %{name}" );
85 StringReplace( str, "%{name}", monster.GetMultiName() );
86 Text text( str, Font::YELLOW_BIG );
87 fheroes2::Point dst_pt( pos.x + ( pos.width - text.w() ) / 2, pos.y + 25 );
88 text.Blit( dst_pt.x, dst_pt.y );
89
90 // sprite monster
91 const int monsterId = monster.GetID();
92 const Bin_Info::MonsterAnimInfo & monsterInfo = Bin_Info::GetMonsterInfo( monsterId );
93 assert( !monsterInfo.animationFrames[Bin_Info::MonsterAnimInfo::STATIC].empty() );
94
95 const fheroes2::Sprite & smon = fheroes2::AGG::GetICN( monster.GetMonsterSprite(), monsterInfo.animationFrames[Bin_Info::MonsterAnimInfo::STATIC][0] );
96 dst_pt.x = pos.x + 80 + smon.x() - ( monster.isWide() ? 22 : 0 );
97 dst_pt.y = pos.y + 135 - smon.height();
98
99 if ( monsterId == Monster::CHAMPION ) {
100 ++dst_pt.x;
101 }
102
103 fheroes2::Blit( smon, display, dst_pt.x, dst_pt.y );
104
105 // info resource
106 // gold
107 const fheroes2::Sprite & sgold = fheroes2::AGG::GetICN( ICN::RESOURCE, 6 );
108 RedrawResourceInfo( sgold, pos.getPosition(), paymentMonster.gold, extres ? 150 : 175, 75, extres ? 183 : 205, 103 );
109 if ( showTotalSum ) {
110 dst_pt.x = pos.x + ( extres ? 105 : 130 );
111 dst_pt.y = pos.y + 200;
112 fheroes2::Blit( sgold, display, dst_pt.x, dst_pt.y );
113 }
114
115 if ( paymentMonster.crystal ) {
116 const fheroes2::Sprite & sres = fheroes2::AGG::GetICN( ICN::RESOURCE, 4 );
117 RedrawResourceInfo( sres, pos.getPosition(), paymentMonster.crystal, 222, 69, 240, 103 );
118 if ( showTotalSum ) {
119 dst_pt.x = pos.x + 177;
120 dst_pt.y = pos.y + 194;
121 fheroes2::Blit( sres, display, dst_pt.x, dst_pt.y );
122 }
123 }
124 else if ( paymentMonster.mercury ) {
125 const fheroes2::Sprite & sres = fheroes2::AGG::GetICN( ICN::RESOURCE, 1 );
126 RedrawResourceInfo( sres, pos.getPosition(), paymentMonster.mercury, 225, 72, 240, 103 );
127 if ( showTotalSum ) {
128 dst_pt.x = pos.x + 180;
129 dst_pt.y = pos.y + 197;
130 fheroes2::Blit( sres, display, dst_pt.x, dst_pt.y );
131 }
132 }
133 else if ( paymentMonster.wood ) {
134 const fheroes2::Sprite & sres = fheroes2::AGG::GetICN( ICN::RESOURCE, 0 );
135 RedrawResourceInfo( sres, pos.getPosition(), paymentMonster.wood, 225, 72, 240, 103 );
136 if ( showTotalSum ) {
137 dst_pt.x = pos.x + 180;
138 dst_pt.y = pos.y + 197;
139 fheroes2::Blit( sres, display, dst_pt.x, dst_pt.y );
140 }
141 }
142 else if ( paymentMonster.ore ) {
143 const fheroes2::Sprite & sres = fheroes2::AGG::GetICN( ICN::RESOURCE, 2 );
144 RedrawResourceInfo( sres, pos.getPosition(), paymentMonster.ore, 225, 72, 240, 103 );
145 if ( showTotalSum ) {
146 dst_pt.x = pos.x + 180;
147 dst_pt.y = pos.y + 197;
148 fheroes2::Blit( sres, display, dst_pt.x, dst_pt.y );
149 }
150 }
151 else if ( paymentMonster.sulfur ) {
152 const fheroes2::Sprite & sres = fheroes2::AGG::GetICN( ICN::RESOURCE, 3 );
153 RedrawResourceInfo( sres, pos.getPosition(), paymentMonster.sulfur, 225, 75, 240, 103 );
154 if ( showTotalSum ) {
155 dst_pt.x = pos.x + 180;
156 dst_pt.y = pos.y + 200;
157 fheroes2::Blit( sres, display, dst_pt.x, dst_pt.y );
158 }
159 }
160 else if ( paymentMonster.gems ) {
161 const fheroes2::Sprite & sres = fheroes2::AGG::GetICN( ICN::RESOURCE, 5 );
162 RedrawResourceInfo( sres, pos.getPosition(), paymentMonster.gems, 225, 75, 240, 103 );
163 if ( showTotalSum ) {
164 dst_pt.x = pos.x + 180;
165 dst_pt.y = pos.y + 200;
166 fheroes2::Blit( sres, display, dst_pt.x, dst_pt.y );
167 }
168 }
169
170 str = _( "Available: %{count}" );
171 StringReplace( str, "%{count}", available );
172 text.Set( str, Font::SMALL );
173 text.Blit( pos.x + 80 - text.w() / 2, pos.y + 135 );
174 }
175
RedrawStaticInfo(const fheroes2::Rect & pos,const Monster & monster,u32 available)176 void RedrawStaticInfo( const fheroes2::Rect & pos, const Monster & monster, u32 available )
177 {
178 fheroes2::Blit( fheroes2::AGG::GetICN( ICN::RECRBKG, 0 ), fheroes2::Display::instance(), pos.x, pos.y );
179
180 RedrawMonsterInfo( pos, monster, available, true );
181
182 // text number buy
183 Text text;
184 text.Set( _( "Number to buy:" ), Font::SMALL );
185 text.Blit( pos.x + 29, pos.y + 163 );
186 }
187
SwitchMaxMinButtons(fheroes2::ButtonBase & btnMax,fheroes2::ButtonBase & btnMin,bool max)188 const char * SwitchMaxMinButtons( fheroes2::ButtonBase & btnMax, fheroes2::ButtonBase & btnMin, bool max )
189 {
190 if ( btnMax.isEnabled() || btnMin.isEnabled() ) {
191 if ( max ) {
192 btnMax.disable();
193 btnMin.enable();
194 }
195 else {
196 btnMin.disable();
197 btnMax.enable();
198 }
199
200 return max ? _( "Max" ) : _( "Min" );
201 }
202
203 return "";
204 }
205
CalculateMax(const Monster & monster,const Kingdom & kingdom,u32 available)206 u32 CalculateMax( const Monster & monster, const Kingdom & kingdom, u32 available )
207 {
208 u32 max = 0;
209 while ( kingdom.AllowPayment( monster.GetCost() * ( max + 1 ) ) && ( max + 1 ) <= available )
210 ++max;
211
212 return max;
213 }
214
RecruitMonster(const Monster & monster0,u32 available,const bool allowDowngradedMonster,const int32_t windowOffsetY)215 Troop Dialog::RecruitMonster( const Monster & monster0, u32 available, const bool allowDowngradedMonster, const int32_t windowOffsetY )
216 {
217 fheroes2::Display & display = fheroes2::Display::instance();
218 LocalEvent & le = LocalEvent::Get();
219
220 // setup cursor
221 const CursorRestorer cursorRestorer( true, Cursor::POINTER );
222
223 // calculate max count
224 Monster monster = monster0;
225 payment_t paymentMonster = monster.GetCost();
226 const Kingdom & kingdom = world.GetKingdom( Settings::Get().CurrentColor() );
227
228 u32 max = CalculateMax( monster, kingdom, available );
229 u32 result = max;
230
231 payment_t paymentCosts( paymentMonster * result );
232 const fheroes2::Sprite & box = fheroes2::AGG::GetICN( ICN::RECRBKG, 0 );
233 const fheroes2::Sprite & boxShadow = fheroes2::AGG::GetICN( ICN::RECRBKG, 1 );
234
235 const fheroes2::Point dialogOffset( ( display.width() - box.width() ) / 2, ( display.height() - box.height() ) / 2 + windowOffsetY );
236 const fheroes2::Point shadowOffset( dialogOffset.x - BORDERWIDTH, dialogOffset.y );
237
238 fheroes2::ImageRestorer back( display, shadowOffset.x, shadowOffset.y, box.width() + BORDERWIDTH, box.height() + BORDERWIDTH );
239 const fheroes2::Rect pos( dialogOffset.x, dialogOffset.y, box.width(), box.height() );
240
241 fheroes2::Blit( boxShadow, display, pos.x - BORDERWIDTH, pos.y + BORDERWIDTH );
242 fheroes2::Blit( box, display, pos.x, pos.y );
243
244 RedrawStaticInfo( pos, monster, available );
245
246 // buttons
247 fheroes2::Point dst_pt;
248
249 dst_pt.x = pos.x + 34;
250 dst_pt.y = pos.y + 249;
251 fheroes2::Button buttonOk( dst_pt.x, dst_pt.y, ICN::RECRUIT, 8, 9 );
252
253 dst_pt.x = pos.x + 187;
254 dst_pt.y = pos.y + 249;
255 fheroes2::Button buttonCancel( dst_pt.x, dst_pt.y, ICN::RECRUIT, 6, 7 );
256
257 dst_pt.x = pos.x + 229;
258 dst_pt.y = pos.y + 156;
259 fheroes2::ButtonSprite buttonMax( dst_pt.x, dst_pt.y, fheroes2::AGG::GetICN( ICN::RECRUIT, 4 ), fheroes2::AGG::GetICN( ICN::RECRUIT, 5 ),
260 fheroes2::AGG::GetICN( ICN::MAX_DISABLED_BUTTON, 0 ) );
261 fheroes2::Button buttonMin( dst_pt.x, dst_pt.y, ICN::NON_UNIFORM_GOOD_MIN_BUTTON, 0, 1 );
262
263 dst_pt.x = pos.x + 205;
264 dst_pt.y = pos.y + 154;
265 fheroes2::Button buttonUp( dst_pt.x, dst_pt.y, ICN::RECRUIT, 0, 1 );
266
267 dst_pt.x = pos.x + 205;
268 dst_pt.y = pos.y + 169;
269 fheroes2::Button buttonDn( dst_pt.x, dst_pt.y, ICN::RECRUIT, 2, 3 );
270
271 fheroes2::TimedEventValidator timedButtonUp( [&buttonUp]() { return buttonUp.isPressed(); } );
272 fheroes2::TimedEventValidator timedButtonDn( [&buttonDn]() { return buttonDn.isPressed(); } );
273
274 buttonDn.subscribe( &timedButtonDn );
275 buttonUp.subscribe( &timedButtonUp );
276
277 const fheroes2::Rect rtWheel( pos.x + 130, pos.y + 155, 100, 30 );
278
279 // Create monster switching arrows
280 fheroes2::ButtonSprite monsterSwitchLeft;
281 fheroes2::ButtonSprite monsterSwitchRight;
282
283 if ( allowDowngradedMonster && monster0.GetDowngrade() != monster0 ) {
284 monsterSwitchLeft.setSprite( fheroes2::AGG::GetICN( ICN::MONSTER_SWITCH_LEFT_ARROW, 0 ), fheroes2::AGG::GetICN( ICN::MONSTER_SWITCH_LEFT_ARROW, 1 ) );
285 monsterSwitchRight.setSprite( fheroes2::AGG::GetICN( ICN::MONSTER_SWITCH_RIGHT_ARROW, 0 ), fheroes2::AGG::GetICN( ICN::MONSTER_SWITCH_RIGHT_ARROW, 1 ) );
286
287 monsterSwitchLeft.setPosition( pos.x + 24, pos.y + 80 );
288 monsterSwitchRight.setPosition( pos.x + 121, pos.y + 80 );
289 }
290 else {
291 monsterSwitchLeft.hide();
292 monsterSwitchRight.hide();
293
294 monsterSwitchLeft.disable();
295 monsterSwitchRight.disable();
296 }
297
298 const fheroes2::Rect monsterArea( pos.x + 40, pos.y + 35, 75, 95 );
299
300 if ( 0 == result ) {
301 buttonOk.disable();
302 buttonMax.disable();
303 buttonMin.disable();
304 buttonMax.draw();
305 }
306
307 const Funds & funds = kingdom.GetFunds();
308 std::string maxmin = SwitchMaxMinButtons( buttonMax, buttonMin, true );
309 RedrawCurrentInfo( pos.getPosition(), result, paymentMonster, paymentCosts, funds, maxmin );
310
311 buttonOk.draw();
312 buttonCancel.draw();
313 if ( buttonMax.isEnabled() )
314 buttonMax.draw();
315 if ( buttonMin.isEnabled() )
316 buttonMin.draw();
317 buttonUp.draw();
318 buttonDn.draw();
319 monsterSwitchLeft.draw();
320 monsterSwitchRight.draw();
321
322 display.render();
323
324 std::vector<Monster> upgrades = { monster0 };
325 while ( upgrades.back().GetDowngrade() != upgrades.back() ) {
326 upgrades.emplace_back( upgrades.back().GetDowngrade() );
327 }
328
329 // str loop
330 while ( le.HandleEvents() ) {
331 bool redraw = false;
332
333 if ( buttonOk.isEnabled() )
334 le.MousePressLeft( buttonOk.area() ) ? buttonOk.drawOnPress() : buttonOk.drawOnRelease();
335 le.MousePressLeft( buttonCancel.area() ) ? buttonCancel.drawOnPress() : buttonCancel.drawOnRelease();
336 le.MousePressLeft( buttonUp.area() ) ? buttonUp.drawOnPress() : buttonUp.drawOnRelease();
337 le.MousePressLeft( buttonDn.area() ) ? buttonDn.drawOnPress() : buttonDn.drawOnRelease();
338
339 le.MousePressLeft( monsterSwitchLeft.area() ) ? monsterSwitchLeft.drawOnPress() : monsterSwitchLeft.drawOnRelease();
340 le.MousePressLeft( monsterSwitchRight.area() ) ? monsterSwitchRight.drawOnPress() : monsterSwitchRight.drawOnRelease();
341
342 if ( buttonMax.isEnabled() )
343 le.MousePressLeft( buttonMax.area() ) ? buttonMax.drawOnPress() : buttonMax.drawOnRelease();
344 if ( buttonMin.isEnabled() )
345 le.MousePressLeft( buttonMin.area() ) ? buttonMin.drawOnPress() : buttonMin.drawOnRelease();
346
347 bool updateCost = false;
348 if ( allowDowngradedMonster && upgrades.size() > 1 ) {
349 if ( le.MouseClickLeft( monsterSwitchLeft.area() ) || le.KeyPress( KEY_LEFT ) ) {
350 for ( size_t i = 0; i < upgrades.size(); ++i ) {
351 if ( upgrades[i] == monster ) {
352 if ( i < upgrades.size() - 1 ) {
353 monster = upgrades[i + 1];
354 }
355 else {
356 monster = upgrades[0];
357 }
358 break;
359 }
360 }
361 updateCost = true;
362 }
363 else if ( le.MouseClickLeft( monsterSwitchRight.area() ) || le.KeyPress( KEY_RIGHT ) ) {
364 for ( size_t i = 0; i < upgrades.size(); ++i ) {
365 if ( upgrades[i] == monster ) {
366 if ( i > 0 ) {
367 monster = upgrades[i - 1];
368 }
369 else {
370 monster = upgrades.back();
371 }
372 break;
373 }
374 }
375 updateCost = true;
376 }
377 }
378
379 if ( updateCost ) {
380 max = CalculateMax( monster, kingdom, available );
381 result = max;
382 paymentMonster = monster.GetCost();
383 paymentCosts = paymentMonster * result;
384 redraw = true;
385 maxmin = SwitchMaxMinButtons( buttonMax, buttonMin, true );
386 }
387
388 bool skipEventCheck = false;
389 if ( le.MousePressRight( monsterArea ) ) {
390 Dialog::ArmyInfo( Troop( monster, available ), Dialog::READONLY );
391 redraw = true;
392 }
393 else if ( le.MouseClickLeft( monsterArea ) ) {
394 Dialog::ArmyInfo( Troop( monster, available ), Dialog::READONLY | Dialog::BUTTONS );
395 redraw = true;
396 skipEventCheck = true;
397 }
398
399 if ( PressIntKey( max, result ) ) {
400 paymentCosts = paymentMonster * result;
401 redraw = true;
402 maxmin.clear();
403
404 if ( result == max ) {
405 maxmin = SwitchMaxMinButtons( buttonMax, buttonMin, true );
406 }
407 else if ( result == 1 ) {
408 maxmin = SwitchMaxMinButtons( buttonMax, buttonMin, false );
409 }
410 }
411
412 if ( ( le.MouseWheelUp( rtWheel ) || le.MouseClickLeft( buttonUp.area() ) || le.KeyPress( KEY_UP ) || timedButtonUp.isDelayPassed() ) && result < max ) {
413 ++result;
414 paymentCosts += paymentMonster;
415 redraw = true;
416 maxmin.clear();
417
418 if ( result == max ) {
419 maxmin = SwitchMaxMinButtons( buttonMax, buttonMin, true );
420 }
421 else if ( result == 1 ) {
422 maxmin = SwitchMaxMinButtons( buttonMax, buttonMin, false );
423 }
424 }
425 else if ( ( le.MouseWheelDn( rtWheel ) || le.MouseClickLeft( buttonDn.area() ) || le.KeyPress( KEY_DOWN ) || timedButtonDn.isDelayPassed() ) && result ) {
426 --result;
427 paymentCosts -= paymentMonster;
428 redraw = true;
429 maxmin.clear();
430
431 if ( result == max ) {
432 maxmin = SwitchMaxMinButtons( buttonMax, buttonMin, true );
433 }
434 else if ( result == 1 ) {
435 maxmin = SwitchMaxMinButtons( buttonMax, buttonMin, false );
436 }
437 }
438 else if ( buttonMax.isEnabled() && le.MouseClickLeft( buttonMax.area() ) && result != max ) {
439 maxmin = SwitchMaxMinButtons( buttonMax, buttonMin, true );
440 result = max;
441 paymentCosts = paymentMonster * max;
442 redraw = true;
443 }
444 else if ( buttonMin.isEnabled() && le.MouseClickLeft( buttonMin.area() ) && result != 1 ) {
445 maxmin = SwitchMaxMinButtons( buttonMax, buttonMin, false );
446 result = 1;
447 paymentCosts = paymentMonster;
448 redraw = true;
449 }
450
451 if ( redraw ) {
452 RedrawStaticInfo( pos, monster, available );
453 RedrawCurrentInfo( pos.getPosition(), result, paymentMonster, paymentCosts, funds, maxmin );
454
455 if ( 0 == result ) {
456 buttonOk.disable();
457 buttonOk.draw();
458 }
459 else {
460 buttonOk.enable();
461 buttonOk.draw();
462 }
463
464 if ( buttonMax.isEnabled() || max == 0 )
465 buttonMax.draw();
466 if ( buttonMin.isEnabled() )
467 buttonMin.draw();
468
469 monsterSwitchLeft.draw();
470 monsterSwitchRight.draw();
471
472 display.render();
473 }
474
475 if ( buttonOk.isEnabled() && ( le.MouseClickLeft( buttonOk.area() ) || Game::HotKeyPressEvent( Game::EVENT_DEFAULT_READY ) ) )
476 break;
477
478 if ( le.MouseClickLeft( buttonCancel.area() ) || ( Game::HotKeyPressEvent( Game::EVENT_DEFAULT_EXIT ) && !skipEventCheck ) ) {
479 result = 0;
480 break;
481 }
482 }
483
484 back.restore();
485 display.render();
486
487 return Troop( monster, result );
488 }
489
DwellingInfo(const Monster & monster,u32 available)490 void Dialog::DwellingInfo( const Monster & monster, u32 available )
491 {
492 fheroes2::Display & display = fheroes2::Display::instance();
493
494 // setup cursor
495 const CursorRestorer cursorRestorer( false, Cursor::POINTER );
496
497 const fheroes2::Sprite & box = fheroes2::AGG::GetICN( ICN::RECR2BKG, 0 );
498 const fheroes2::Sprite & boxShadow = fheroes2::AGG::GetICN( ICN::RECR2BKG, 1 );
499
500 const fheroes2::Point dialogOffset( ( display.width() - box.width() ) / 2, display.height() / 2 - display.DEFAULT_HEIGHT / 2 + BORDERWIDTH );
501 const fheroes2::Point shadowOffset( dialogOffset.x - BORDERWIDTH, dialogOffset.y );
502
503 fheroes2::ImageRestorer back( display, shadowOffset.x, shadowOffset.y, box.width() + BORDERWIDTH, box.height() + BORDERWIDTH );
504 const fheroes2::Rect pos( dialogOffset.x, dialogOffset.y, box.width(), box.height() );
505
506 fheroes2::Blit( boxShadow, display, pos.x - BORDERWIDTH, pos.y + BORDERWIDTH );
507 fheroes2::Blit( box, display, pos.x, pos.y );
508
509 LocalEvent & le = LocalEvent::Get();
510
511 RedrawMonsterInfo( pos, monster, available, false );
512
513 display.render();
514
515 while ( le.HandleEvents() && le.MousePressRight() )
516 ;
517
518 back.restore();
519 display.render();
520 }
521