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 <algorithm>
24 #include <array>
25 
26 #include "agg.h"
27 #include "agg_image.h"
28 #include "ai.h"
29 #include "battle_board.h"
30 #include "battle_tower.h"
31 #include "castle.h"
32 #include "castle_building_info.h"
33 #include "dialog.h"
34 #include "difficulty.h"
35 #include "game.h"
36 #include "game_static.h"
37 #include "ground.h"
38 #include "icn.h"
39 #include "kingdom.h"
40 #include "logging.h"
41 #include "luck.h"
42 #include "m82.h"
43 #include "maps_tiles.h"
44 #include "morale.h"
45 #include "payment.h"
46 #include "profit.h"
47 #include "race.h"
48 #include "serialize.h"
49 #include "settings.h"
50 #include "text.h"
51 #include "tools.h"
52 #include "translations.h"
53 #include "world.h"
54 
55 namespace
56 {
57     const size_t maximumCastles = 72;
58 
59     const std::array<const char *, maximumCastles> defaultCastleNames
60         = { gettext_noop( "Blackridge" ),   gettext_noop( "Pinehurst" ),   gettext_noop( "Woodhaven" ),    gettext_noop( "Hillstone" ),  gettext_noop( "Whiteshield" ),
61             gettext_noop( "Bloodreign" ),   gettext_noop( "Dragontooth" ), gettext_noop( "Greywind" ),     gettext_noop( "Blackwind" ),  gettext_noop( "Portsmith" ),
62             gettext_noop( "Middle Gate" ),  gettext_noop( "Tundara" ),     gettext_noop( "Vulcania" ),     gettext_noop( "Sansobar" ),   gettext_noop( "Atlantium" ),
63             gettext_noop( "Baywatch" ),     gettext_noop( "Wildabar" ),    gettext_noop( "Fountainhead" ), gettext_noop( "Vertigo" ),    gettext_noop( "Winterkill" ),
64             gettext_noop( "Nightshadow" ),  gettext_noop( "Sandcaster" ),  gettext_noop( "Lakeside" ),     gettext_noop( "Olympus" ),    gettext_noop( "Brindamoor" ),
65             gettext_noop( "Burlock" ),      gettext_noop( "Xabran" ),      gettext_noop( "Dragadune" ),    gettext_noop( "Alamar" ),     gettext_noop( "Kalindra" ),
66             gettext_noop( "Blackfang" ),    gettext_noop( "Basenji" ),     gettext_noop( "Algary" ),       gettext_noop( "Sorpigal" ),   gettext_noop( "New Dawn" ),
67             gettext_noop( "Erliquin" ),     gettext_noop( "Avone" ),       gettext_noop( "Big Oak" ),      gettext_noop( "Hampshire" ),  gettext_noop( "Chandler" ),
68             gettext_noop( "South Mill" ),   gettext_noop( "Weed Patch" ),  gettext_noop( "Roc Haven" ),    gettext_noop( "Avalon" ),     gettext_noop( "Antioch" ),
69             gettext_noop( "Brownston" ),    gettext_noop( "Weddington" ),  gettext_noop( "Whittingham" ),  gettext_noop( "Westfork" ),   gettext_noop( "Hilltop" ),
70             gettext_noop( "Yorksford" ),    gettext_noop( "Sherman" ),     gettext_noop( "Roscomon" ),     gettext_noop( "Elk's Head" ), gettext_noop( "Cathcart" ),
71             gettext_noop( "Viper's Nest" ), gettext_noop( "Pig's Eye" ),   gettext_noop( "Blacksford" ),   gettext_noop( "Burton" ),     gettext_noop( "Blackburn" ),
72             gettext_noop( "Lankershire" ),  gettext_noop( "Lombard" ),     gettext_noop( "Timberhill" ),   gettext_noop( "Fenton" ),     gettext_noop( "Troy" ),
73             gettext_noop( "Forder Oaks" ),  gettext_noop( "Meramec" ),     gettext_noop( "Quick Silver" ), gettext_noop( "Westmoor" ),   gettext_noop( "Willow" ),
74             gettext_noop( "Sheltemburg" ),  gettext_noop( "Corackston" ) };
75 }
76 
Castle()77 Castle::Castle()
78     : race( Race::NONE )
79     , building( 0 )
80     , captain( *this )
81     , army( nullptr )
82 {
83     std::fill( dwelling, dwelling + CASTLEMAXMONSTER, 0 );
84     army.SetCommander( &captain );
85 }
86 
Castle(s32 cx,s32 cy,int rc)87 Castle::Castle( s32 cx, s32 cy, int rc )
88     : MapPosition( fheroes2::Point( cx, cy ) )
89     , race( rc )
90     , building( 0 )
91     , captain( *this )
92     , army( nullptr )
93 {
94     std::fill( dwelling, dwelling + CASTLEMAXMONSTER, 0 );
95     army.SetCommander( &captain );
96 }
97 
LoadFromMP2(std::vector<uint8_t> & data)98 void Castle::LoadFromMP2( std::vector<uint8_t> & data )
99 {
100     StreamBuf st( data );
101 
102     switch ( st.get() ) {
103     case 0:
104         SetColor( Color::BLUE );
105         break;
106     case 1:
107         SetColor( Color::GREEN );
108         break;
109     case 2:
110         SetColor( Color::RED );
111         break;
112     case 3:
113         SetColor( Color::YELLOW );
114         break;
115     case 4:
116         SetColor( Color::ORANGE );
117         break;
118     case 5:
119         SetColor( Color::PURPLE );
120         break;
121     default:
122         SetColor( Color::NONE );
123         break;
124     }
125 
126     // custom building
127     if ( st.get() ) {
128         // building
129         int build = st.getLE16();
130         if ( 0x0002 & build )
131             building |= BUILD_THIEVESGUILD;
132         if ( 0x0004 & build )
133             building |= BUILD_TAVERN;
134         if ( 0x0008 & build )
135             building |= BUILD_SHIPYARD;
136         if ( 0x0010 & build )
137             building |= BUILD_WELL;
138         if ( 0x0080 & build )
139             building |= BUILD_STATUE;
140         if ( 0x0100 & build )
141             building |= BUILD_LEFTTURRET;
142         if ( 0x0200 & build )
143             building |= BUILD_RIGHTTURRET;
144         if ( 0x0400 & build )
145             building |= BUILD_MARKETPLACE;
146         if ( 0x1000 & build )
147             building |= BUILD_MOAT;
148         if ( 0x0800 & build )
149             building |= BUILD_WEL2;
150         if ( 0x2000 & build )
151             building |= BUILD_SPEC;
152 
153         // dwelling
154         int dwell = st.getLE16();
155         if ( 0x0008 & dwell )
156             building |= DWELLING_MONSTER1;
157         if ( 0x0010 & dwell )
158             building |= DWELLING_MONSTER2;
159         if ( 0x0020 & dwell )
160             building |= DWELLING_MONSTER3;
161         if ( 0x0040 & dwell )
162             building |= DWELLING_MONSTER4;
163         if ( 0x0080 & dwell )
164             building |= DWELLING_MONSTER5;
165         if ( 0x0100 & dwell )
166             building |= DWELLING_MONSTER6;
167         if ( 0x0200 & dwell )
168             building |= DWELLING_UPGRADE2 | DWELLING_MONSTER2;
169         if ( 0x0400 & dwell )
170             building |= DWELLING_UPGRADE3 | DWELLING_MONSTER3;
171         if ( 0x0800 & dwell )
172             building |= DWELLING_UPGRADE4 | DWELLING_MONSTER4;
173         if ( 0x1000 & dwell )
174             building |= DWELLING_UPGRADE5 | DWELLING_MONSTER5;
175         if ( 0x2000 & dwell )
176             building |= DWELLING_UPGRADE6 | DWELLING_MONSTER6;
177 
178         // magic tower
179         int level = st.get();
180         if ( 0 < level )
181             building |= BUILD_MAGEGUILD1;
182         if ( 1 < level )
183             building |= BUILD_MAGEGUILD2;
184         if ( 2 < level )
185             building |= BUILD_MAGEGUILD3;
186         if ( 3 < level )
187             building |= BUILD_MAGEGUILD4;
188         if ( 4 < level )
189             building |= BUILD_MAGEGUILD5;
190     }
191     else {
192         st.skip( 5 );
193 
194         // default building
195         building |= DWELLING_MONSTER1;
196         u32 dwelling2 = 0;
197         switch ( Game::getDifficulty() ) {
198         case Difficulty::EASY:
199             dwelling2 = 75;
200             break;
201         case Difficulty::NORMAL:
202             dwelling2 = 50;
203             break;
204         case Difficulty::HARD:
205             dwelling2 = 25;
206             break;
207         case Difficulty::EXPERT:
208             dwelling2 = 10;
209             break;
210         default:
211             break;
212         }
213         if ( dwelling2 && dwelling2 >= Rand::Get( 1, 100 ) )
214             building |= DWELLING_MONSTER2;
215     }
216 
217     // custom troops
218     bool custom_troops = ( st.get() != 0 );
219     if ( custom_troops ) {
220         Troop troops[5];
221 
222         // set monster id
223         for ( Troop & troop : troops )
224             troop.SetMonster( st.get() + 1 );
225 
226         // set count
227         for ( Troop & troop : troops )
228             troop.SetCount( st.getLE16() );
229 
230         army.Assign( troops, std::end( troops ) );
231         SetModes( CUSTOMARMY );
232     }
233     else
234         st.skip( 15 );
235 
236     // captain
237     if ( st.get() )
238         building |= BUILD_CAPTAIN;
239 
240     // custom name
241     st.skip( 1 );
242     name = st.toString( 13 );
243 
244     // race
245     u32 kingdom_race = Players::GetPlayerRace( GetColor() );
246     switch ( st.get() ) {
247     case 0:
248         race = Race::KNGT;
249         break;
250     case 1:
251         race = Race::BARB;
252         break;
253     case 2:
254         race = Race::SORC;
255         break;
256     case 3:
257         race = Race::WRLK;
258         break;
259     case 4:
260         race = Race::WZRD;
261         break;
262     case 5:
263         race = Race::NECR;
264         break;
265     default:
266         race = ( Color::NONE != GetColor() && ( Race::ALL & kingdom_race ) ? kingdom_race : Race::Rand() );
267         break;
268     }
269 
270     // castle
271     building |= st.get() ? BUILD_CASTLE : BUILD_TENT;
272 
273     // allow upgrade to castle (0 - true, 1 - false)
274     if ( st.get() )
275         ResetModes( ALLOWCASTLE );
276     else
277         SetModes( ALLOWCASTLE );
278 
279     // unknown 29 byte
280     //
281 
282     PostLoad();
283 }
284 
PostLoad(void)285 void Castle::PostLoad( void )
286 {
287     // dwelling pack
288     if ( building & DWELLING_MONSTER1 )
289         dwelling[0] = Monster( race, DWELLING_MONSTER1 ).GetGrown();
290     if ( building & DWELLING_MONSTER2 )
291         dwelling[1] = Monster( race, DWELLING_MONSTER2 ).GetGrown();
292     if ( building & DWELLING_UPGRADE2 )
293         dwelling[1] = Monster( race, DWELLING_UPGRADE2 ).GetGrown();
294     if ( building & DWELLING_MONSTER3 )
295         dwelling[2] = Monster( race, DWELLING_MONSTER3 ).GetGrown();
296     if ( building & DWELLING_UPGRADE3 )
297         dwelling[2] = Monster( race, DWELLING_UPGRADE3 ).GetGrown();
298     if ( building & DWELLING_MONSTER4 )
299         dwelling[3] = Monster( race, DWELLING_MONSTER4 ).GetGrown();
300     if ( building & DWELLING_UPGRADE4 )
301         dwelling[3] = Monster( race, DWELLING_UPGRADE4 ).GetGrown();
302     if ( building & DWELLING_MONSTER5 )
303         dwelling[4] = Monster( race, DWELLING_MONSTER5 ).GetGrown();
304     if ( building & DWELLING_UPGRADE5 )
305         dwelling[4] = Monster( race, DWELLING_UPGRADE5 ).GetGrown();
306     if ( building & DWELLING_MONSTER6 )
307         dwelling[5] = Monster( race, DWELLING_MONSTER6 ).GetGrown();
308     if ( building & DWELLING_UPGRADE6 )
309         dwelling[5] = Monster( race, DWELLING_UPGRADE6 ).GetGrown();
310     if ( building & DWELLING_UPGRADE7 )
311         dwelling[5] = Monster( race, DWELLING_UPGRADE7 ).GetGrown();
312 
313     // fix upgrade dwelling dependend from race
314     switch ( race ) {
315     case Race::BARB:
316         building &= ~( DWELLING_UPGRADE3 | DWELLING_UPGRADE6 );
317         break;
318     case Race::SORC:
319         building &= ~( DWELLING_UPGRADE5 | DWELLING_UPGRADE6 );
320         break;
321     case Race::WRLK:
322         building &= ~( DWELLING_UPGRADE2 | DWELLING_UPGRADE3 | DWELLING_UPGRADE5 );
323         break;
324     case Race::WZRD:
325         building &= ~( DWELLING_UPGRADE2 | DWELLING_UPGRADE4 );
326         break;
327     case Race::NECR:
328         building &= ~( DWELLING_UPGRADE6 );
329         break;
330     default:
331         break;
332     }
333 
334     army.SetColor( GetColor() );
335 
336     // fix captain
337     if ( building & BUILD_CAPTAIN )
338         captain.LoadDefaults( HeroBase::CAPTAIN, race );
339 
340     // MageGuild
341     mageguild.initialize( race, HaveLibraryCapability() );
342     // educate heroes and captain
343     EducateHeroes();
344 
345     // AI troops auto pack for gray towns
346     if ( Color::NONE == GetColor() && !Modes( CUSTOMARMY ) ) {
347         // towns get 4 reinforcements at the start of the game
348         for ( int i = 0; i < 4; ++i )
349             JoinRNDArmy();
350     }
351 
352     // fix shipyard
353     if ( !HaveNearlySea() )
354         building &= ~( BUILD_SHIPYARD );
355 
356     // remove tavern from necromancer castle
357     if ( Race::NECR == race && ( building & BUILD_TAVERN ) ) {
358         building &= ~BUILD_TAVERN;
359         if ( Settings::Get().isCurrentMapPriceOfLoyalty() )
360             building |= BUILD_SHRINE;
361     }
362 
363     SetModes( ALLOWBUILD );
364 
365     // end
366     DEBUG_LOG( DBG_GAME, DBG_INFO,
367                ( building & BUILD_CASTLE ? "castle" : "town" ) << ": " << name << ", color: " << Color::String( GetColor() ) << ", race: " << Race::String( race ) );
368 }
369 
GetCaptain(void)370 Captain & Castle::GetCaptain( void )
371 {
372     return captain;
373 }
374 
GetCaptain(void) const375 const Captain & Castle::GetCaptain( void ) const
376 {
377     return captain;
378 }
379 
isCastle(void) const380 bool Castle::isCastle( void ) const
381 {
382     return ( building & BUILD_CASTLE ) != 0;
383 }
384 
isCapital(void) const385 bool Castle::isCapital( void ) const
386 {
387     return Modes( CAPITAL );
388 }
389 
CountBuildings(void) const390 u32 Castle::CountBuildings( void ) const
391 {
392     const u32 tavern = ( race == Race::NECR ? ( Settings::Get().isCurrentMapPriceOfLoyalty() ? BUILD_SHRINE : BUILD_NOTHING ) : BUILD_TAVERN );
393 
394     return CountBits( building
395                       & ( BUILD_THIEVESGUILD | tavern | BUILD_SHIPYARD | BUILD_WELL | BUILD_STATUE | BUILD_LEFTTURRET | BUILD_RIGHTTURRET | BUILD_MARKETPLACE | BUILD_WEL2
396                           | BUILD_MOAT | BUILD_SPEC | BUILD_CAPTAIN | BUILD_CASTLE | BUILD_MAGEGUILD1 | DWELLING_MONSTER1 | DWELLING_MONSTER2 | DWELLING_MONSTER3
397                           | DWELLING_MONSTER4 | DWELLING_MONSTER5 | DWELLING_MONSTER6 ) );
398 }
399 
isPosition(const fheroes2::Point & pt) const400 bool Castle::isPosition( const fheroes2::Point & pt ) const
401 {
402     const fheroes2::Point & mp = GetCenter();
403 
404     /*
405               -
406              ---
407             -+++-
408             ++X++
409     */
410 
411     return ( ( pt.x >= mp.x - 1 && pt.x <= mp.x + 1 && ( pt.y == mp.y - 1 || pt.y == mp.y ) ) || ( ( pt.x == mp.x - 2 || pt.x == mp.x + 2 ) && pt.y == mp.y ) );
412 }
413 
EducateHeroes(void)414 void Castle::EducateHeroes( void )
415 {
416     // for learns new spells need 1 day
417     if ( GetLevelMageGuild() ) {
418         CastleHeroes heroes = world.GetHeroes( *this );
419 
420         if ( heroes.FullHouse() ) {
421             MageGuildEducateHero( *heroes.Guest() );
422             MageGuildEducateHero( *heroes.Guard() );
423         }
424         else if ( heroes.IsValid() )
425             MageGuildEducateHero( *heroes.GuestFirst() );
426 
427         // captain
428         if ( captain.isValid() )
429             MageGuildEducateHero( captain );
430     }
431 }
432 
getBuildingValue() const433 int Castle::getBuildingValue() const
434 {
435     int value = CountBuildings();
436 
437     // Additional value for the most important buildings
438     if ( isBuild( BUILD_CASTLE ) )
439         value += 5;
440 
441     if ( isBuild( DWELLING_MONSTER6 ) )
442         value += 6;
443 
444     if ( race == Race::WRLK && isBuild( DWELLING_UPGRADE7 ) )
445         value += 2;
446 
447     // DWELLING_UPGRADE7 resolves to a negative, can't use <= operator
448     for ( uint32_t upgrade = DWELLING_UPGRADE2; upgrade <= DWELLING_UPGRADE6; upgrade <<= 1 ) {
449         if ( isBuild( upgrade ) )
450             ++value;
451     }
452 
453     int increase = 1;
454     for ( uint32_t guild = BUILD_MAGEGUILD2; guild <= BUILD_MAGEGUILD5; guild <<= 1 ) {
455         if ( isBuild( guild ) )
456             value += increase;
457         ++increase;
458     }
459 
460     return value;
461 }
462 
getVisitValue(const Heroes & hero) const463 double Castle::getVisitValue( const Heroes & hero ) const
464 {
465     double spellValue = 0;
466     const SpellStorage & guildSpells = mageguild.GetSpells( GetLevelMageGuild(), isLibraryBuild() );
467     for ( const Spell & spell : guildSpells ) {
468         if ( spell.isAdventure() ) {
469             // AI is stupid to use Adventure spells.
470             continue;
471         }
472         if ( hero.CanLearnSpell( spell ) && !hero.HaveSpell( spell, true ) ) {
473             spellValue += spell.Level() * 50.0;
474         }
475     }
476 
477     const Troops & heroArmy = hero.GetArmy();
478     Troops futureArmy( heroArmy );
479     const double heroArmyStrength = futureArmy.GetStrength();
480 
481     Funds potentialFunds = GetKingdom().GetFunds();
482 
483     for ( size_t i = 0; i < futureArmy.Size(); ++i ) {
484         Troop * monster = futureArmy.GetTroop( i );
485         if ( monster != nullptr && monster->isValid() ) {
486             const payment_t payment = monster->GetUpgradeCost();
487 
488             if ( GetRace() == monster->GetRace() && isBuild( monster->GetUpgrade().GetDwelling() ) && potentialFunds >= payment ) {
489                 potentialFunds -= payment;
490                 monster->Upgrade();
491             }
492         }
493     }
494 
495     const double upgradeStrength = futureArmy.GetStrength() - heroArmyStrength;
496 
497     Troops reinforcement;
498     for ( uint32_t dw = DWELLING_MONSTER6; dw >= DWELLING_MONSTER1; dw >>= 1 ) {
499         if ( isBuild( dw ) ) {
500             const Monster monster( race, GetActualDwelling( dw ) );
501             const uint32_t available = getMonstersInDwelling( dw );
502 
503             uint32_t couldRecruit = potentialFunds.getLowestQuotient( monster.GetCost() );
504             if ( available < couldRecruit )
505                 couldRecruit = available;
506 
507             potentialFunds -= ( monster.GetCost() * couldRecruit );
508 
509             reinforcement.PushBack( monster, couldRecruit );
510         }
511     }
512 
513     return spellValue + upgradeStrength + futureArmy.getReinforcementValue( reinforcement );
514 }
515 
ActionNewDay(void)516 void Castle::ActionNewDay( void )
517 {
518     EducateHeroes();
519 
520     SetModes( ALLOWBUILD );
521 }
522 
GetDwelling(u32 dw)523 u32 * Castle::GetDwelling( u32 dw )
524 {
525     if ( isBuild( dw ) )
526         switch ( dw ) {
527         case DWELLING_MONSTER1:
528             return &dwelling[0];
529         case DWELLING_MONSTER2:
530         case DWELLING_UPGRADE2:
531             return &dwelling[1];
532         case DWELLING_MONSTER3:
533         case DWELLING_UPGRADE3:
534             return &dwelling[2];
535         case DWELLING_MONSTER4:
536         case DWELLING_UPGRADE4:
537             return &dwelling[3];
538         case DWELLING_MONSTER5:
539         case DWELLING_UPGRADE5:
540             return &dwelling[4];
541         case DWELLING_MONSTER6:
542         case DWELLING_UPGRADE6:
543         case DWELLING_UPGRADE7:
544             return &dwelling[5];
545         default:
546             break;
547         }
548     return nullptr;
549 }
550 
ActionNewWeek(void)551 void Castle::ActionNewWeek( void )
552 {
553     // skip the first week
554     if ( world.CountWeek() < 2 ) {
555         return;
556     }
557 
558     const bool isNeutral = GetColor() == Color::NONE;
559 
560     // increase population
561     if ( world.GetWeekType().GetType() != WeekName::PLAGUE ) {
562         const u32 dwellings1[] = { DWELLING_MONSTER1, DWELLING_MONSTER2, DWELLING_MONSTER3, DWELLING_MONSTER4, DWELLING_MONSTER5, DWELLING_MONSTER6, 0 };
563         u32 * dw = nullptr;
564 
565         // simple growth
566         for ( u32 ii = 0; dwellings1[ii]; ++ii )
567             if ( nullptr != ( dw = GetDwelling( dwellings1[ii] ) ) ) {
568                 u32 growth = Monster( race, GetActualDwelling( dwellings1[ii] ) ).GetGrown();
569 
570                 // well build
571                 if ( building & BUILD_WELL )
572                     growth += GetGrownWell();
573 
574                 // wel2 extras
575                 if ( ( dwellings1[ii] == DWELLING_MONSTER1 ) && ( building & BUILD_WEL2 ) )
576                     growth += GetGrownWel2();
577 
578                 if ( isControlAI() )
579                     growth = static_cast<uint32_t>( growth * Difficulty::GetUnitGrowthBonus( Game::getDifficulty() ) );
580 
581                 // neutral town: half population (normal for begin month)
582                 if ( isNeutral && !world.BeginMonth() )
583                     growth /= 2;
584 
585                 *dw += growth;
586             }
587 
588         // Week Of
589         if ( world.GetWeekType().GetType() == WeekName::MONSTERS && !world.BeginMonth() ) {
590             const u32 dwellings2[] = { DWELLING_MONSTER1, DWELLING_UPGRADE2, DWELLING_UPGRADE3, DWELLING_UPGRADE4, DWELLING_UPGRADE5,
591                                        DWELLING_MONSTER2, DWELLING_MONSTER3, DWELLING_MONSTER4, DWELLING_MONSTER5, 0 };
592 
593             for ( u32 ii = 0; dwellings2[ii]; ++ii )
594                 if ( nullptr != ( dw = GetDwelling( dwellings2[ii] ) ) ) {
595                     const Monster mons( race, dwellings2[ii] );
596                     if ( mons.isValid() && mons.GetID() == world.GetWeekType().GetMonster() ) {
597                         *dw += GetGrownWeekOf();
598                         break;
599                     }
600                 }
601         }
602 
603         // neutral town: increase garrisons
604         if ( isNeutral && !Modes( CUSTOMARMY ) ) {
605             JoinRNDArmy();
606             // if it's a town there's 40% chance (or it's a castle) to get extra troops
607             if ( isCastle() || Rand::Get( 1, 100 ) <= 40 )
608                 JoinRNDArmy();
609         }
610     }
611 }
612 
ActionNewMonth(void)613 void Castle::ActionNewMonth( void )
614 {
615     // skip the first month
616     if ( world.GetMonth() < 2 ) {
617         return;
618     }
619 
620     // population halved
621     if ( world.GetWeekType().GetType() == WeekName::PLAGUE ) {
622         for ( u32 ii = 0; ii < CASTLEMAXMONSTER; ++ii )
623             dwelling[ii] /= 2;
624     }
625     else
626         // Month Of
627         if ( world.GetWeekType().GetType() == WeekName::MONSTERS ) {
628         const u32 dwellings[] = { DWELLING_MONSTER1, DWELLING_UPGRADE2, DWELLING_UPGRADE3, DWELLING_UPGRADE4, DWELLING_UPGRADE5,
629                                   DWELLING_MONSTER2, DWELLING_MONSTER3, DWELLING_MONSTER4, DWELLING_MONSTER5, 0 };
630         u32 * dw = nullptr;
631 
632         for ( u32 ii = 0; dwellings[ii]; ++ii )
633             if ( nullptr != ( dw = GetDwelling( dwellings[ii] ) ) ) {
634                 const Monster mons( race, dwellings[ii] );
635                 if ( mons.isValid() && mons.GetID() == world.GetWeekType().GetMonster() ) {
636                     *dw += *dw * GetGrownMonthOf() / 100;
637                     break;
638                 }
639             }
640     }
641 }
642 
643 // change castle color
ChangeColor(int cl)644 void Castle::ChangeColor( int cl )
645 {
646     SetColor( cl );
647     army.SetColor( cl );
648 }
649 
650 // return mage guild level
GetLevelMageGuild(void) const651 int Castle::GetLevelMageGuild( void ) const
652 {
653     if ( building & BUILD_MAGEGUILD5 )
654         return 5;
655     else if ( building & BUILD_MAGEGUILD4 )
656         return 4;
657     else if ( building & BUILD_MAGEGUILD3 )
658         return 3;
659     else if ( building & BUILD_MAGEGUILD2 )
660         return 2;
661     else if ( building & BUILD_MAGEGUILD1 )
662         return 1;
663 
664     return 0;
665 }
666 
GetMageGuild(void) const667 const MageGuild & Castle::GetMageGuild( void ) const
668 {
669     return mageguild;
670 }
671 
HaveLibraryCapability(void) const672 bool Castle::HaveLibraryCapability( void ) const
673 {
674     return race == Race::WZRD;
675 }
676 
isLibraryBuild(void) const677 bool Castle::isLibraryBuild( void ) const
678 {
679     return race == Race::WZRD && isBuild( BUILD_SPEC );
680 }
681 
MageGuildEducateHero(HeroBase & hero) const682 void Castle::MageGuildEducateHero( HeroBase & hero ) const
683 {
684     mageguild.educateHero( hero, GetLevelMageGuild(), isLibraryBuild() );
685 }
686 
isFortificationBuild() const687 bool Castle::isFortificationBuild() const
688 {
689     return race == Race::KNGT && isBuild( BUILD_SPEC );
690 }
691 
GetStringBuilding(u32 build,int race)692 const char * Castle::GetStringBuilding( u32 build, int race )
693 {
694     return fheroes2::getBuildingName( race, static_cast<building_t>( build ) );
695 }
696 
GetDescriptionBuilding(u32 build,int race)697 const char * Castle::GetDescriptionBuilding( u32 build, int race )
698 {
699     return fheroes2::getBuildingDescription( race, static_cast<building_t>( build ) );
700 }
701 
AllowBuyHero(const Heroes & hero,std::string * msg) const702 bool Castle::AllowBuyHero( const Heroes & hero, std::string * msg ) const
703 {
704     CastleHeroes heroes = world.GetHeroes( *this );
705 
706     if ( heroes.Guest() ) {
707         // allow recruit with auto move guest to guard
708         if ( Settings::Get().ExtCastleAllowGuardians() && !heroes.Guard() ) {
709             if ( !heroes.Guest()->GetArmy().CanJoinTroops( army ) ) {
710                 if ( msg )
711                     *msg = _( "Cannot recruit - guest to guard automove error." );
712                 return false;
713             }
714         }
715         else {
716             if ( msg )
717                 *msg = _( "Cannot recruit - you already have a Hero in this town." );
718             return false;
719         }
720     }
721 
722     const Kingdom & myKingdom = GetKingdom();
723     if ( !myKingdom.AllowRecruitHero( false, hero.GetLevel() ) ) {
724         if ( msg )
725             *msg = _( "Cannot recruit - you have too many Heroes." );
726         return false;
727     }
728 
729     if ( !myKingdom.AllowRecruitHero( true, hero.GetLevel() ) ) {
730         if ( msg )
731             *msg = _( "Cannot afford a Hero" );
732         return false;
733     }
734 
735     return true;
736 }
737 
RecruitHero(Heroes * hero)738 Heroes * Castle::RecruitHero( Heroes * hero )
739 {
740     if ( !hero || !AllowBuyHero( *hero ) )
741         return nullptr;
742 
743     CastleHeroes heroes = world.GetHeroes( *this );
744     if ( heroes.Guest() ) {
745         if ( Settings::Get().ExtCastleAllowGuardians() && !heroes.Guard() ) {
746             // move guest to guard
747             SwapCastleHeroes( heroes );
748         }
749         else
750             return nullptr;
751     }
752 
753     // recruit
754     if ( !hero->Recruit( *this ) )
755         return nullptr;
756 
757     // actually update available heroes to recruit
758     const Colors colors( Settings::Get().GetPlayers().GetActualColors() );
759 
760     for ( const int kingdomColor : colors ) {
761         Kingdom & kingdom = world.GetKingdom( kingdomColor );
762         if ( kingdom.GetLastLostHero() == hero )
763             kingdom.ResetLastLostHero();
764 
765         kingdom.GetRecruits();
766     }
767 
768     Kingdom & currentKingdom = GetKingdom();
769     currentKingdom.OddFundsResource( PaymentConditions::RecruitHero( hero->GetLevel() ) );
770 
771     // update spell book
772     if ( GetLevelMageGuild() )
773         MageGuildEducateHero( *hero );
774 
775     DEBUG_LOG( DBG_GAME, DBG_INFO, name << ", recruit: " << hero->GetName() );
776 
777     return hero;
778 }
779 
780 /* recruit monster from building to castle army */
RecruitMonster(const Troop & troop,bool showDialog)781 bool Castle::RecruitMonster( const Troop & troop, bool showDialog )
782 {
783     if ( !troop.isValid() )
784         return false;
785 
786     int dwellingIndex = 0;
787 
788     switch ( troop.GetDwelling() ) {
789     case DWELLING_MONSTER1:
790         dwellingIndex = 0;
791         break;
792     case DWELLING_UPGRADE2:
793     case DWELLING_MONSTER2:
794         dwellingIndex = 1;
795         break;
796     case DWELLING_UPGRADE3:
797     case DWELLING_MONSTER3:
798         dwellingIndex = 2;
799         break;
800     case DWELLING_UPGRADE4:
801     case DWELLING_MONSTER4:
802         dwellingIndex = 3;
803         break;
804     case DWELLING_UPGRADE5:
805     case DWELLING_MONSTER5:
806         dwellingIndex = 4;
807         break;
808     case DWELLING_UPGRADE7:
809     case DWELLING_UPGRADE6:
810     case DWELLING_MONSTER6:
811         dwellingIndex = 5;
812         break;
813     default:
814         return false;
815     }
816 
817     uint32_t count = troop.GetCount();
818 
819     // fix count
820     if ( dwelling[dwellingIndex] < count )
821         count = dwelling[dwellingIndex];
822 
823     // buy
824     const payment_t paymentCosts = troop.GetCost();
825     Kingdom & kingdom = GetKingdom();
826 
827     if ( !kingdom.AllowPayment( paymentCosts ) )
828         return false;
829 
830     // first: guard army join
831     if ( !GetArmy().JoinTroop( troop ) ) {
832         CastleHeroes heroes = world.GetHeroes( *this );
833 
834         if ( !heroes.Guest() || !heroes.Guest()->GetArmy().JoinTroop( troop ) ) {
835             if ( showDialog ) {
836                 Dialog::Message( "", _( "There is no room in the garrison for this army." ), Font::BIG, Dialog::OK );
837             }
838             return false;
839         }
840     }
841 
842     kingdom.OddFundsResource( paymentCosts );
843     dwelling[dwellingIndex] -= count;
844 
845     DEBUG_LOG( DBG_GAME, DBG_TRACE, name << " recruit: " << troop.GetMultiName() << "(" << count << ")" );
846 
847     return true;
848 }
849 
RecruitMonsterFromDwelling(uint32_t dw,uint32_t count,bool force)850 bool Castle::RecruitMonsterFromDwelling( uint32_t dw, uint32_t count, bool force )
851 {
852     Monster monster( race, GetActualDwelling( dw ) );
853     Troop troop( monster, std::min( count, getRecruitLimit( monster, GetKingdom().GetFunds() ) ) );
854 
855     if ( !RecruitMonster( troop, false ) ) {
856         if ( force ) {
857             Troop * weak = GetArmy().GetWeakestTroop();
858             if ( weak && weak->GetStrength() < troop.GetStrength() ) {
859                 DEBUG_LOG( DBG_GAME, DBG_INFO,
860                            name << ": " << troop.GetCount() << " " << troop.GetMultiName() << " replace " << weak->GetCount() << " " << weak->GetMultiName() );
861                 weak->Set( troop );
862                 return true;
863             }
864         }
865 
866         return false;
867     }
868     return true;
869 }
870 
recruitBestAvailable(Funds budget)871 void Castle::recruitBestAvailable( Funds budget )
872 {
873     for ( uint32_t dw = DWELLING_MONSTER6; dw >= DWELLING_MONSTER1; dw >>= 1 ) {
874         if ( isBuild( dw ) ) {
875             const Monster monster( race, GetActualDwelling( dw ) );
876             const uint32_t willRecruit = getRecruitLimit( monster, budget );
877 
878             if ( RecruitMonsterFromDwelling( dw, willRecruit, true ) ) {
879                 // success, reduce the budget
880                 budget -= ( monster.GetCost() * willRecruit );
881             }
882         }
883     }
884 }
885 
getRecruitLimit(const Monster & monster,const Funds & budget) const886 uint32_t Castle::getRecruitLimit( const Monster & monster, const Funds & budget ) const
887 {
888     // validate that monster is from the current castle
889     if ( monster.GetRace() != race )
890         return 0;
891 
892     const uint32_t available = getMonstersInDwelling( monster.GetDwelling() );
893 
894     uint32_t willRecruit = budget.getLowestQuotient( monster.GetCost() );
895     if ( available < willRecruit )
896         return available;
897 
898     return willRecruit;
899 }
900 
901 /* return current count monster in dwelling */
getMonstersInDwelling(u32 dw) const902 u32 Castle::getMonstersInDwelling( u32 dw ) const
903 {
904     switch ( dw ) {
905     case DWELLING_MONSTER1:
906         return dwelling[0];
907     case DWELLING_MONSTER2:
908     case DWELLING_UPGRADE2:
909         return dwelling[1];
910     case DWELLING_MONSTER3:
911     case DWELLING_UPGRADE3:
912         return dwelling[2];
913     case DWELLING_MONSTER4:
914     case DWELLING_UPGRADE4:
915         return dwelling[3];
916     case DWELLING_MONSTER5:
917     case DWELLING_UPGRADE5:
918         return dwelling[4];
919     case DWELLING_MONSTER6:
920     case DWELLING_UPGRADE6:
921     case DWELLING_UPGRADE7:
922         return dwelling[5];
923 
924     default:
925         break;
926     }
927 
928     return 0;
929 }
930 
931 /* return requirement for building */
GetBuildingRequirement(u32 build) const932 u32 Castle::GetBuildingRequirement( u32 build ) const
933 {
934     u32 requirement = 0;
935 
936     switch ( build ) {
937     case BUILD_SPEC:
938         switch ( race ) {
939         case Race::WZRD:
940             requirement |= BUILD_MAGEGUILD1;
941             break;
942 
943         default:
944             break;
945         }
946         break;
947 
948     case DWELLING_MONSTER2:
949         switch ( race ) {
950         case Race::KNGT:
951         case Race::BARB:
952         case Race::WZRD:
953         case Race::WRLK:
954         case Race::NECR:
955             requirement |= DWELLING_MONSTER1;
956             break;
957 
958         case Race::SORC:
959             requirement |= DWELLING_MONSTER1;
960             requirement |= BUILD_TAVERN;
961             break;
962 
963         default:
964             break;
965         }
966         break;
967 
968     case DWELLING_MONSTER3:
969         switch ( race ) {
970         case Race::KNGT:
971             requirement |= DWELLING_MONSTER1;
972             requirement |= BUILD_WELL;
973             break;
974 
975         case Race::BARB:
976         case Race::SORC:
977         case Race::WZRD:
978         case Race::WRLK:
979         case Race::NECR:
980             requirement |= DWELLING_MONSTER1;
981             break;
982 
983         default:
984             break;
985         }
986         break;
987 
988     case DWELLING_MONSTER4:
989         switch ( race ) {
990         case Race::KNGT:
991             requirement |= DWELLING_MONSTER1;
992             requirement |= BUILD_TAVERN;
993             break;
994 
995         case Race::BARB:
996             requirement |= DWELLING_MONSTER1;
997             break;
998 
999         case Race::SORC:
1000             requirement |= DWELLING_MONSTER3;
1001             requirement |= BUILD_MAGEGUILD1;
1002             break;
1003 
1004         case Race::WZRD:
1005         case Race::WRLK:
1006             requirement |= DWELLING_MONSTER2;
1007             break;
1008 
1009         case Race::NECR:
1010             requirement |= DWELLING_MONSTER3;
1011             requirement |= BUILD_THIEVESGUILD;
1012             break;
1013 
1014         default:
1015             break;
1016         }
1017         break;
1018 
1019     case DWELLING_MONSTER5:
1020         switch ( race ) {
1021         case Race::KNGT:
1022         case Race::BARB:
1023             requirement |= DWELLING_MONSTER2;
1024             requirement |= DWELLING_MONSTER3;
1025             requirement |= DWELLING_MONSTER4;
1026             break;
1027 
1028         case Race::SORC:
1029             requirement |= DWELLING_MONSTER4;
1030             break;
1031 
1032         case Race::WRLK:
1033             requirement |= DWELLING_MONSTER3;
1034             break;
1035 
1036         case Race::WZRD:
1037             requirement |= DWELLING_MONSTER3;
1038             requirement |= BUILD_MAGEGUILD1;
1039             break;
1040 
1041         case Race::NECR:
1042             requirement |= DWELLING_MONSTER2;
1043             requirement |= BUILD_MAGEGUILD1;
1044             break;
1045 
1046         default:
1047             break;
1048         }
1049         break;
1050 
1051     case DWELLING_MONSTER6:
1052         switch ( race ) {
1053         case Race::KNGT:
1054             requirement |= DWELLING_MONSTER2;
1055             requirement |= DWELLING_MONSTER3;
1056             requirement |= DWELLING_MONSTER4;
1057             break;
1058 
1059         case Race::BARB:
1060         case Race::SORC:
1061         case Race::NECR:
1062             requirement |= DWELLING_MONSTER5;
1063             break;
1064 
1065         case Race::WRLK:
1066         case Race::WZRD:
1067             requirement |= DWELLING_MONSTER4;
1068             requirement |= DWELLING_MONSTER5;
1069             break;
1070 
1071         default:
1072             break;
1073         }
1074         break;
1075 
1076     case DWELLING_UPGRADE2:
1077         switch ( race ) {
1078         case Race::KNGT:
1079         case Race::BARB:
1080             requirement |= DWELLING_MONSTER2;
1081             requirement |= DWELLING_MONSTER3;
1082             requirement |= DWELLING_MONSTER4;
1083             break;
1084 
1085         case Race::SORC:
1086             requirement |= DWELLING_MONSTER2;
1087             requirement |= BUILD_WELL;
1088             break;
1089 
1090         case Race::NECR:
1091             requirement |= DWELLING_MONSTER2;
1092             break;
1093 
1094         default:
1095             break;
1096         }
1097         break;
1098 
1099     case DWELLING_UPGRADE3:
1100         switch ( race ) {
1101         case Race::KNGT:
1102             requirement |= DWELLING_MONSTER2;
1103             requirement |= DWELLING_MONSTER3;
1104             requirement |= DWELLING_MONSTER4;
1105             break;
1106 
1107         case Race::SORC:
1108             requirement |= DWELLING_MONSTER3;
1109             requirement |= DWELLING_MONSTER4;
1110             break;
1111 
1112         case Race::WZRD:
1113             requirement |= DWELLING_MONSTER3;
1114             requirement |= BUILD_WELL;
1115             break;
1116 
1117         case Race::NECR:
1118             requirement |= DWELLING_MONSTER3;
1119             break;
1120 
1121         default:
1122             break;
1123         }
1124         break;
1125 
1126     case DWELLING_UPGRADE4:
1127         switch ( race ) {
1128         case Race::KNGT:
1129         case Race::BARB:
1130             requirement |= DWELLING_MONSTER2;
1131             requirement |= DWELLING_MONSTER3;
1132             requirement |= DWELLING_MONSTER4;
1133             break;
1134 
1135         case Race::SORC:
1136         case Race::WRLK:
1137         case Race::NECR:
1138             requirement |= DWELLING_MONSTER4;
1139             break;
1140 
1141         default:
1142             break;
1143         }
1144         break;
1145 
1146     case DWELLING_UPGRADE5:
1147         switch ( race ) {
1148         case Race::KNGT:
1149             requirement |= DWELLING_MONSTER5;
1150             break;
1151 
1152         case Race::BARB:
1153             requirement |= DWELLING_MONSTER5;
1154             break;
1155 
1156         case Race::WZRD:
1157             requirement |= BUILD_SPEC;
1158             requirement |= DWELLING_MONSTER5;
1159             break;
1160 
1161         case Race::NECR:
1162             requirement |= BUILD_MAGEGUILD2;
1163             requirement |= DWELLING_MONSTER5;
1164             break;
1165 
1166         default:
1167             break;
1168         }
1169         break;
1170 
1171     case DWELLING_UPGRADE6:
1172         switch ( race ) {
1173         case Race::KNGT:
1174             requirement |= DWELLING_MONSTER6;
1175             break;
1176 
1177         case Race::WRLK:
1178         case Race::WZRD:
1179             requirement |= DWELLING_MONSTER6;
1180             break;
1181 
1182         default:
1183             break;
1184         }
1185         break;
1186     case DWELLING_UPGRADE7:
1187         if ( race == Race::WRLK )
1188             requirement |= DWELLING_UPGRADE6;
1189         break;
1190 
1191     default:
1192         break;
1193     }
1194 
1195     return requirement;
1196 }
1197 
1198 /* check allow buy building */
CheckBuyBuilding(u32 build) const1199 int Castle::CheckBuyBuilding( u32 build ) const
1200 {
1201     if ( build & building )
1202         return ALREADY_BUILT;
1203 
1204     switch ( build ) {
1205     // allow build castle
1206     case BUILD_CASTLE:
1207         if ( !Modes( ALLOWCASTLE ) )
1208             return BUILD_DISABLE;
1209         break;
1210     // buid shipyard only nearly sea
1211     case BUILD_SHIPYARD:
1212         if ( !HaveNearlySea() )
1213             return BUILD_DISABLE;
1214         break;
1215     case BUILD_SHRINE:
1216         if ( Race::NECR != GetRace() || !Settings::Get().isCurrentMapPriceOfLoyalty() )
1217             return BUILD_DISABLE;
1218         break;
1219     case BUILD_TAVERN:
1220         if ( Race::NECR == GetRace() )
1221             return BUILD_DISABLE;
1222         break;
1223 
1224     default:
1225         break;
1226     }
1227 
1228     if ( !Modes( ALLOWBUILD ) )
1229         return NOT_TODAY;
1230 
1231     if ( isCastle() ) {
1232         if ( build == BUILD_TENT )
1233             return BUILD_DISABLE;
1234     }
1235     else {
1236         if ( build != BUILD_CASTLE )
1237             return NEED_CASTLE;
1238     }
1239 
1240     switch ( build ) {
1241         // check upgrade dwelling
1242     case DWELLING_UPGRADE2:
1243         if ( ( Race::WRLK | Race::WZRD ) & race )
1244             return UNKNOWN_UPGRADE;
1245         break;
1246     case DWELLING_UPGRADE3:
1247         if ( ( Race::BARB | Race::WRLK ) & race )
1248             return UNKNOWN_UPGRADE;
1249         break;
1250     case DWELLING_UPGRADE4:
1251         if ( (Race::WZRD)&race )
1252             return UNKNOWN_UPGRADE;
1253         break;
1254     case DWELLING_UPGRADE5:
1255         if ( ( Race::SORC | Race::WRLK ) & race )
1256             return UNKNOWN_UPGRADE;
1257         break;
1258     case DWELLING_UPGRADE6:
1259         if ( ( Race::BARB | Race::SORC | Race::NECR ) & race )
1260             return UNKNOWN_UPGRADE;
1261         break;
1262     case DWELLING_UPGRADE7:
1263         if ( Race::WRLK != race )
1264             return UNKNOWN_UPGRADE;
1265         break;
1266 
1267     default:
1268         break;
1269     }
1270 
1271     // check build requirements
1272     const u32 requirement = Castle::GetBuildingRequirement( build );
1273 
1274     for ( u32 itr = 0x00000001; itr; itr <<= 1 )
1275         if ( ( requirement & itr ) && !( building & itr ) )
1276             return REQUIRES_BUILD;
1277 
1278     // check valid payment
1279     if ( !GetKingdom().AllowPayment( PaymentConditions::BuyBuilding( race, build ) ) )
1280         return LACK_RESOURCES;
1281 
1282     return ALLOW_BUILD;
1283 }
1284 
GetAllBuildingStatus(const Castle & castle)1285 int Castle::GetAllBuildingStatus( const Castle & castle )
1286 {
1287     if ( !castle.Modes( ALLOWBUILD ) )
1288         return NOT_TODAY;
1289     if ( !castle.isCastle() )
1290         return NEED_CASTLE;
1291 
1292     const u32 rest = ~castle.building;
1293 
1294     for ( u32 itr = 0x00000001; itr; itr <<= 1 )
1295         if ( ( rest & itr ) && ( ALLOW_BUILD == castle.CheckBuyBuilding( itr ) ) )
1296             return ALLOW_BUILD;
1297 
1298     for ( u32 itr = 0x00000001; itr; itr <<= 1 )
1299         if ( ( rest & itr ) && ( LACK_RESOURCES == castle.CheckBuyBuilding( itr ) ) )
1300             return LACK_RESOURCES;
1301 
1302     for ( u32 itr = 0x00000001; itr; itr <<= 1 )
1303         if ( ( rest & itr ) && ( REQUIRES_BUILD == castle.CheckBuyBuilding( itr ) ) )
1304             return REQUIRES_BUILD;
1305 
1306     return UNKNOWN_COND;
1307 }
1308 
AllowBuyBuilding(u32 build) const1309 bool Castle::AllowBuyBuilding( u32 build ) const
1310 {
1311     return ALLOW_BUILD == CheckBuyBuilding( build );
1312 }
1313 
1314 /* buy building */
BuyBuilding(u32 build)1315 bool Castle::BuyBuilding( u32 build )
1316 {
1317     if ( !AllowBuyBuilding( build ) )
1318         return false;
1319 
1320     GetKingdom().OddFundsResource( PaymentConditions::BuyBuilding( race, build ) );
1321 
1322     // add build
1323     building |= build;
1324 
1325     switch ( build ) {
1326     case BUILD_CASTLE:
1327         building &= ~BUILD_TENT;
1328         Maps::UpdateCastleSprite( GetCenter(), race );
1329         Maps::ClearFog( GetIndex(), Game::GetViewDistance( Game::VIEW_CASTLE ), GetColor() );
1330         break;
1331 
1332     case BUILD_MAGEGUILD1:
1333     case BUILD_MAGEGUILD2:
1334     case BUILD_MAGEGUILD3:
1335     case BUILD_MAGEGUILD4:
1336     case BUILD_MAGEGUILD5:
1337         EducateHeroes();
1338         break;
1339 
1340     case BUILD_CAPTAIN:
1341         captain.LoadDefaults( HeroBase::CAPTAIN, race );
1342         if ( GetLevelMageGuild() )
1343             MageGuildEducateHero( captain );
1344         break;
1345 
1346     case BUILD_SPEC:
1347         // build library
1348         if ( HaveLibraryCapability() )
1349             EducateHeroes();
1350         break;
1351 
1352     case DWELLING_MONSTER1:
1353         dwelling[0] = Monster( race, DWELLING_MONSTER1 ).GetGrown();
1354         break;
1355     case DWELLING_MONSTER2:
1356         dwelling[1] = Monster( race, DWELLING_MONSTER2 ).GetGrown();
1357         break;
1358     case DWELLING_MONSTER3:
1359         dwelling[2] = Monster( race, DWELLING_MONSTER3 ).GetGrown();
1360         break;
1361     case DWELLING_MONSTER4:
1362         dwelling[3] = Monster( race, DWELLING_MONSTER4 ).GetGrown();
1363         break;
1364     case DWELLING_MONSTER5:
1365         dwelling[4] = Monster( race, DWELLING_MONSTER5 ).GetGrown();
1366         break;
1367     case DWELLING_MONSTER6:
1368         dwelling[5] = Monster( race, DWELLING_MONSTER6 ).GetGrown();
1369         break;
1370     default:
1371         break;
1372     }
1373 
1374     // disable day build
1375     ResetModes( ALLOWBUILD );
1376 
1377     DEBUG_LOG( DBG_GAME, DBG_INFO, name << " build " << GetStringBuilding( build, race ) );
1378     return true;
1379 }
1380 
1381 /* draw image castle to position */
DrawImageCastle(const fheroes2::Point & pt) const1382 void Castle::DrawImageCastle( const fheroes2::Point & pt ) const
1383 {
1384     fheroes2::Display & display = fheroes2::Display::instance();
1385     const Maps::Tiles & tile = world.GetTiles( GetIndex() );
1386 
1387     u32 index = 0;
1388     fheroes2::Point dst_pt;
1389 
1390     // draw ground
1391     switch ( tile.GetGround() ) {
1392     case Maps::Ground::GRASS:
1393         index = 0;
1394         break;
1395     case Maps::Ground::SNOW:
1396         index = 10;
1397         break;
1398     case Maps::Ground::SWAMP:
1399         index = 20;
1400         break;
1401     case Maps::Ground::LAVA:
1402         index = 30;
1403         break;
1404     case Maps::Ground::DESERT:
1405         index = 40;
1406         break;
1407     case Maps::Ground::DIRT:
1408         index = 50;
1409         break;
1410     case Maps::Ground::WASTELAND:
1411         index = 60;
1412         break;
1413     case Maps::Ground::BEACH:
1414         index = 70;
1415         break;
1416 
1417     default:
1418         return;
1419     }
1420 
1421     for ( u32 ii = 0; ii < 5; ++ii ) {
1422         const fheroes2::Sprite & sprite = fheroes2::AGG::GetICN( ICN::OBJNTWBA, index + ii );
1423         dst_pt.x = pt.x + ii * 32 + sprite.x();
1424         dst_pt.y = pt.y + 3 * 32 + sprite.y();
1425         fheroes2::Blit( sprite, display, dst_pt.x, dst_pt.y );
1426     }
1427 
1428     for ( u32 ii = 0; ii < 5; ++ii ) {
1429         const fheroes2::Sprite & sprite = fheroes2::AGG::GetICN( ICN::OBJNTWBA, index + 5 + ii );
1430         dst_pt.x = pt.x + ii * 32 + sprite.x();
1431         dst_pt.y = pt.y + 4 * 32 + sprite.y();
1432         fheroes2::Blit( sprite, display, dst_pt.x, dst_pt.y );
1433     }
1434 
1435     // draw castle
1436     switch ( race ) {
1437     case Race::KNGT:
1438         index = 0;
1439         break;
1440     case Race::BARB:
1441         index = 32;
1442         break;
1443     case Race::SORC:
1444         index = 64;
1445         break;
1446     case Race::WRLK:
1447         index = 96;
1448         break;
1449     case Race::WZRD:
1450         index = 128;
1451         break;
1452     case Race::NECR:
1453         index = 160;
1454         break;
1455     default:
1456         break;
1457     }
1458     if ( !( BUILD_CASTLE & building ) )
1459         index += 16;
1460     const fheroes2::Sprite & sprite2 = fheroes2::AGG::GetICN( ICN::OBJNTOWN, index );
1461     dst_pt.x = pt.x + 2 * 32 + sprite2.x();
1462     dst_pt.y = pt.y + sprite2.y();
1463     fheroes2::Blit( sprite2, display, dst_pt.x, dst_pt.y );
1464     for ( u32 ii = 0; ii < 5; ++ii ) {
1465         const fheroes2::Sprite & sprite = fheroes2::AGG::GetICN( ICN::OBJNTOWN, index + 1 + ii );
1466         dst_pt.x = pt.x + ii * 32 + sprite.x();
1467         dst_pt.y = pt.y + 32 + sprite.y();
1468         fheroes2::Blit( sprite, display, dst_pt.x, dst_pt.y );
1469     }
1470     for ( u32 ii = 0; ii < 5; ++ii ) {
1471         const fheroes2::Sprite & sprite = fheroes2::AGG::GetICN( ICN::OBJNTOWN, index + 6 + ii );
1472         dst_pt.x = pt.x + ii * 32 + sprite.x();
1473         dst_pt.y = pt.y + 2 * 32 + sprite.y();
1474         fheroes2::Blit( sprite, display, dst_pt.x, dst_pt.y );
1475     }
1476     for ( u32 ii = 0; ii < 5; ++ii ) {
1477         const fheroes2::Sprite & sprite = fheroes2::AGG::GetICN( ICN::OBJNTOWN, index + 11 + ii );
1478         dst_pt.x = pt.x + ii * 32 + sprite.x();
1479         dst_pt.y = pt.y + 3 * 32 + sprite.y();
1480         fheroes2::Blit( sprite, display, dst_pt.x, dst_pt.y );
1481     }
1482 }
1483 
GetICNBoat(int race)1484 int Castle::GetICNBoat( int race )
1485 {
1486     switch ( race ) {
1487     case Race::BARB:
1488         return ICN::TWNBBOAT;
1489     case Race::KNGT:
1490         return ICN::TWNKBOAT;
1491     case Race::NECR:
1492         return ICN::TWNNBOAT;
1493     case Race::SORC:
1494         return ICN::TWNSBOAT;
1495     case Race::WRLK:
1496         return ICN::TWNWBOAT;
1497     case Race::WZRD:
1498         return ICN::TWNZBOAT;
1499     default:
1500         break;
1501     }
1502 
1503     DEBUG_LOG( DBG_GAME, DBG_WARN, "return unknown" );
1504     return ICN::UNKNOWN;
1505 }
1506 
1507 /* get building name ICN */
GetICNBuilding(u32 build,int race)1508 int Castle::GetICNBuilding( u32 build, int race )
1509 {
1510     if ( Race::BARB == race ) {
1511         switch ( build ) {
1512         case BUILD_CASTLE:
1513             return ICN::TWNBCSTL;
1514         case BUILD_TENT:
1515             return ICN::TWNBTENT;
1516         case BUILD_SPEC:
1517             return ICN::TWNBSPEC;
1518         case BUILD_CAPTAIN:
1519             return ICN::TWNBCAPT;
1520         case BUILD_WEL2:
1521             return ICN::TWNBWEL2;
1522         case BUILD_LEFTTURRET:
1523             return ICN::TWNBLTUR;
1524         case BUILD_RIGHTTURRET:
1525             return ICN::TWNBRTUR;
1526         case BUILD_MOAT:
1527             return ICN::TWNBMOAT;
1528         case BUILD_MARKETPLACE:
1529             return ICN::TWNBMARK;
1530         case BUILD_THIEVESGUILD:
1531             return ICN::TWNBTHIE;
1532         case BUILD_TAVERN:
1533             return ICN::TWNBTVRN;
1534         case BUILD_WELL:
1535             return ICN::TWNBWELL;
1536         case BUILD_STATUE:
1537             return ICN::TWNBSTAT;
1538         case BUILD_SHIPYARD:
1539             return ICN::TWNBDOCK;
1540         case BUILD_MAGEGUILD1:
1541         case BUILD_MAGEGUILD2:
1542         case BUILD_MAGEGUILD3:
1543         case BUILD_MAGEGUILD4:
1544         case BUILD_MAGEGUILD5:
1545             return ICN::TWNBMAGE;
1546         case DWELLING_MONSTER1:
1547             return ICN::TWNBDW_0;
1548         case DWELLING_MONSTER2:
1549             return ICN::TWNBDW_1;
1550         case DWELLING_UPGRADE2:
1551             return ICN::TWNBUP_1;
1552         case DWELLING_MONSTER3:
1553             return ICN::TWNBDW_2;
1554         case DWELLING_MONSTER4:
1555             return ICN::TWNBDW_3;
1556         case DWELLING_UPGRADE4:
1557             return ICN::TWNBUP_3;
1558         case DWELLING_MONSTER5:
1559             return ICN::TWNBDW_4;
1560         case DWELLING_UPGRADE5:
1561             return ICN::TWNBUP_4;
1562         case DWELLING_MONSTER6:
1563             return ICN::TWNBDW_5;
1564         default:
1565             break;
1566         }
1567     }
1568     else if ( Race::KNGT == race ) {
1569         switch ( build ) {
1570         case BUILD_CASTLE:
1571             return ICN::TWNKCSTL;
1572         case BUILD_TENT:
1573             return ICN::TWNKTENT;
1574         case BUILD_SPEC:
1575             return ICN::TWNKSPEC;
1576         case BUILD_CAPTAIN:
1577             return ICN::TWNKCAPT;
1578         case BUILD_WEL2:
1579             return ICN::KNIGHT_CASTLE_RIGHT_FARM;
1580         case BUILD_LEFTTURRET:
1581             return ICN::TWNKLTUR;
1582         case BUILD_RIGHTTURRET:
1583             return ICN::TWNKRTUR;
1584         case BUILD_MOAT:
1585             return ICN::TWNKMOAT;
1586         case BUILD_MARKETPLACE:
1587             return ICN::TWNKMARK;
1588         case BUILD_THIEVESGUILD:
1589             return ICN::TWNKTHIE;
1590         case BUILD_TAVERN:
1591             return ICN::TWNKTVRN;
1592         case BUILD_WELL:
1593             return ICN::TWNKWELL;
1594         case BUILD_STATUE:
1595             return ICN::TWNKSTAT;
1596         case BUILD_SHIPYARD:
1597             return ICN::TWNKDOCK;
1598         case BUILD_MAGEGUILD1:
1599         case BUILD_MAGEGUILD2:
1600         case BUILD_MAGEGUILD3:
1601         case BUILD_MAGEGUILD4:
1602         case BUILD_MAGEGUILD5:
1603             return ICN::TWNKMAGE;
1604         case DWELLING_MONSTER1:
1605             return ICN::TWNKDW_0;
1606         case DWELLING_MONSTER2:
1607             return ICN::TWNKDW_1;
1608         case DWELLING_UPGRADE2:
1609             return ICN::TWNKUP_1;
1610         case DWELLING_MONSTER3:
1611             return ICN::TWNKDW_2;
1612         case DWELLING_UPGRADE3:
1613             return ICN::TWNKUP_2;
1614         case DWELLING_MONSTER4:
1615             return ICN::TWNKDW_3;
1616         case DWELLING_UPGRADE4:
1617             return ICN::TWNKUP_3;
1618         case DWELLING_MONSTER5:
1619             return ICN::TWNKDW_4;
1620         case DWELLING_UPGRADE5:
1621             return ICN::TWNKUP_4;
1622         case DWELLING_MONSTER6:
1623             return ICN::TWNKDW_5;
1624         case DWELLING_UPGRADE6:
1625             return ICN::TWNKUP_5;
1626         default:
1627             break;
1628         }
1629     }
1630     else if ( Race::NECR == race ) {
1631         switch ( build ) {
1632         case BUILD_CASTLE:
1633             return ICN::TWNNCSTL;
1634         case BUILD_TENT:
1635             return ICN::TWNNTENT;
1636         case BUILD_SPEC:
1637             return ICN::TWNNSPEC;
1638         case BUILD_CAPTAIN:
1639             return ICN::NECROMANCER_CASTLE_STANDALONE_CAPTAIN_QUARTERS;
1640         case BUILD_WEL2:
1641             return ICN::TWNNWEL2;
1642         case BUILD_LEFTTURRET:
1643             return ICN::TWNNLTUR;
1644         case BUILD_RIGHTTURRET:
1645             return ICN::TWNNRTUR;
1646         case BUILD_MOAT:
1647             return ICN::TWNNMOAT;
1648         case BUILD_MARKETPLACE:
1649             return ICN::TWNNMARK;
1650         case BUILD_THIEVESGUILD:
1651             return ICN::TWNNTHIE;
1652         // shrine
1653         case BUILD_SHRINE:
1654             return ICN::TWNNTVRN;
1655         case BUILD_WELL:
1656             return ICN::TWNNWELL;
1657         case BUILD_STATUE:
1658             return ICN::TWNNSTAT;
1659         case BUILD_SHIPYARD:
1660             return ICN::TWNNDOCK;
1661         case BUILD_MAGEGUILD1:
1662         case BUILD_MAGEGUILD2:
1663         case BUILD_MAGEGUILD3:
1664         case BUILD_MAGEGUILD4:
1665         case BUILD_MAGEGUILD5:
1666             return ICN::TWNNMAGE;
1667         case DWELLING_MONSTER1:
1668             return ICN::TWNNDW_0;
1669         case DWELLING_MONSTER2:
1670             return ICN::TWNNDW_1;
1671         case DWELLING_UPGRADE2:
1672             return ICN::TWNNUP_1;
1673         case DWELLING_MONSTER3:
1674             return ICN::TWNNDW_2;
1675         case DWELLING_UPGRADE3:
1676             return ICN::TWNNUP_2;
1677         case DWELLING_MONSTER4:
1678             return ICN::TWNNDW_3;
1679         case DWELLING_UPGRADE4:
1680             return ICN::TWNNUP_3;
1681         case DWELLING_MONSTER5:
1682             return ICN::TWNNDW_4;
1683         case DWELLING_UPGRADE5:
1684             return ICN::TWNNUP_4;
1685         case DWELLING_MONSTER6:
1686             return ICN::TWNNDW_5;
1687         default:
1688             break;
1689         }
1690     }
1691     else if ( Race::SORC == race ) {
1692         switch ( build ) {
1693         case BUILD_CASTLE:
1694             return ICN::TWNSCSTL;
1695         case BUILD_TENT:
1696             return ICN::TWNSTENT;
1697         case BUILD_SPEC:
1698             return ICN::TWNSSPEC;
1699         case BUILD_CAPTAIN:
1700             return ICN::TWNSCAPT;
1701         case BUILD_WEL2:
1702             return ICN::TWNSWEL2;
1703         case BUILD_LEFTTURRET:
1704             return ICN::TWNSLTUR;
1705         case BUILD_RIGHTTURRET:
1706             return ICN::TWNSRTUR;
1707         case BUILD_MOAT:
1708             return ICN::TWNSMOAT;
1709         case BUILD_MARKETPLACE:
1710             return ICN::TWNSMARK;
1711         case BUILD_THIEVESGUILD:
1712             return ICN::TWNSTHIE;
1713         case BUILD_TAVERN:
1714             return ICN::TWNSTVRN;
1715         case BUILD_WELL:
1716             return ICN::TWNSWELL;
1717         case BUILD_STATUE:
1718             return ICN::TWNSSTAT;
1719         case BUILD_SHIPYARD:
1720             return ICN::TWNSDOCK;
1721         case BUILD_MAGEGUILD1:
1722         case BUILD_MAGEGUILD2:
1723         case BUILD_MAGEGUILD3:
1724         case BUILD_MAGEGUILD4:
1725         case BUILD_MAGEGUILD5:
1726             return ICN::TWNSMAGE;
1727         case DWELLING_MONSTER1:
1728             return ICN::TWNSDW_0;
1729         case DWELLING_MONSTER2:
1730             return ICN::TWNSDW_1;
1731         case DWELLING_UPGRADE2:
1732             return ICN::TWNSUP_1;
1733         case DWELLING_MONSTER3:
1734             return ICN::TWNSDW_2;
1735         case DWELLING_UPGRADE3:
1736             return ICN::TWNSUP_2;
1737         case DWELLING_MONSTER4:
1738             return ICN::TWNSDW_3;
1739         case DWELLING_UPGRADE4:
1740             return ICN::TWNSUP_3;
1741         case DWELLING_MONSTER5:
1742             return ICN::TWNSDW_4;
1743         case DWELLING_MONSTER6:
1744             return ICN::TWNSDW_5;
1745         default:
1746             break;
1747         }
1748     }
1749     else if ( Race::WRLK == race ) {
1750         switch ( build ) {
1751         case BUILD_CASTLE:
1752             return ICN::TWNWCSTL;
1753         case BUILD_TENT:
1754             return ICN::TWNWTENT;
1755         case BUILD_SPEC:
1756             return ICN::TWNWSPEC;
1757         case BUILD_CAPTAIN:
1758             return ICN::TWNWCAPT;
1759         case BUILD_WEL2:
1760             return ICN::TWNWWEL2;
1761         case BUILD_LEFTTURRET:
1762             return ICN::TWNWLTUR;
1763         case BUILD_RIGHTTURRET:
1764             return ICN::TWNWRTUR;
1765         case BUILD_MOAT:
1766             return ICN::TWNWMOAT;
1767         case BUILD_MARKETPLACE:
1768             return ICN::TWNWMARK;
1769         case BUILD_THIEVESGUILD:
1770             return ICN::TWNWTHIE;
1771         case BUILD_TAVERN:
1772             return ICN::TWNWTVRN;
1773         case BUILD_WELL:
1774             return ICN::TWNWWELL;
1775         case BUILD_STATUE:
1776             return ICN::TWNWSTAT;
1777         case BUILD_SHIPYARD:
1778             return ICN::TWNWDOCK;
1779         case BUILD_MAGEGUILD1:
1780         case BUILD_MAGEGUILD2:
1781         case BUILD_MAGEGUILD3:
1782         case BUILD_MAGEGUILD4:
1783         case BUILD_MAGEGUILD5:
1784             return ICN::TWNWMAGE;
1785         case DWELLING_MONSTER1:
1786             return ICN::TWNWDW_0;
1787         case DWELLING_MONSTER2:
1788             return ICN::TWNWDW_1;
1789         case DWELLING_MONSTER3:
1790             return ICN::TWNWDW_2;
1791         case DWELLING_MONSTER4:
1792             return ICN::TWNWDW_3;
1793         case DWELLING_UPGRADE4:
1794             return ICN::TWNWUP_3;
1795         case DWELLING_MONSTER5:
1796             return ICN::TWNWDW_4;
1797         case DWELLING_MONSTER6:
1798             return ICN::TWNWDW_5;
1799         case DWELLING_UPGRADE6:
1800             return ICN::TWNWUP_5;
1801         case DWELLING_UPGRADE7:
1802             return ICN::TWNWUP5B;
1803         default:
1804             break;
1805         }
1806     }
1807     else if ( Race::WZRD == race ) {
1808         switch ( build ) {
1809         case BUILD_CASTLE:
1810             return ICN::TWNZCSTL;
1811         case BUILD_TENT:
1812             return ICN::TWNZTENT;
1813         case BUILD_SPEC:
1814             return ICN::TWNZSPEC;
1815         case BUILD_CAPTAIN:
1816             return ICN::TWNZCAPT;
1817         case BUILD_WEL2:
1818             return ICN::TWNZWEL2;
1819         case BUILD_LEFTTURRET:
1820             return ICN::TWNZLTUR;
1821         case BUILD_RIGHTTURRET:
1822             return ICN::TWNZRTUR;
1823         case BUILD_MOAT:
1824             return ICN::TWNZMOAT;
1825         case BUILD_MARKETPLACE:
1826             return ICN::TWNZMARK;
1827         case BUILD_THIEVESGUILD:
1828             return ICN::TWNZTHIE;
1829         case BUILD_TAVERN:
1830             return ICN::TWNZTVRN;
1831         case BUILD_WELL:
1832             return ICN::TWNZWELL;
1833         case BUILD_STATUE:
1834             return ICN::TWNZSTAT;
1835         case BUILD_SHIPYARD:
1836             return ICN::TWNZDOCK;
1837         case BUILD_MAGEGUILD1:
1838         case BUILD_MAGEGUILD2:
1839         case BUILD_MAGEGUILD3:
1840         case BUILD_MAGEGUILD4:
1841         case BUILD_MAGEGUILD5:
1842             return ICN::TWNZMAGE;
1843         case DWELLING_MONSTER1:
1844             return ICN::TWNZDW_0;
1845         case DWELLING_MONSTER2:
1846             return ICN::TWNZDW_1;
1847         case DWELLING_MONSTER3:
1848             return ICN::TWNZDW_2;
1849         case DWELLING_UPGRADE3:
1850             return ICN::TWNZUP_2;
1851         case DWELLING_MONSTER4:
1852             return ICN::TWNZDW_3;
1853         case DWELLING_MONSTER5:
1854             return ICN::TWNZDW_4;
1855         case DWELLING_UPGRADE5:
1856             return ICN::TWNZUP_4;
1857         case DWELLING_MONSTER6:
1858             return ICN::TWNZDW_5;
1859         case DWELLING_UPGRADE6:
1860             return ICN::TWNZUP_5;
1861         default:
1862             break;
1863         }
1864     }
1865 
1866     DEBUG_LOG( DBG_GAME, DBG_WARN,
1867                "return unknown"
1868                    << ", race: " << Race::String( race ) << ", build: " << Castle::GetStringBuilding( build, race ) << ", " << build );
1869 
1870     return ICN::UNKNOWN;
1871 }
1872 
GetHeroes(void) const1873 CastleHeroes Castle::GetHeroes( void ) const
1874 {
1875     return world.GetHeroes( *this );
1876 }
1877 
HaveNearlySea(void) const1878 bool Castle::HaveNearlySea( void ) const
1879 {
1880     // check nearest ocean
1881     if ( Maps::isValidAbsPoint( center.x, center.y + 2 ) ) {
1882         const s32 index = Maps::GetIndexFromAbsPoint( center.x, center.y + 2 );
1883         const Maps::Tiles & left = world.GetTiles( index - 1 );
1884         const Maps::Tiles & right = world.GetTiles( index + 1 );
1885         const Maps::Tiles & middle = world.GetTiles( index );
1886 
1887         return left.isWater() || right.isWater() || middle.isWater();
1888     }
1889     return false;
1890 }
1891 
TilePresentBoat(const Maps::Tiles & tile)1892 bool TilePresentBoat( const Maps::Tiles & tile )
1893 {
1894     return tile.isWater() && ( tile.GetObject() == MP2::OBJ_BOAT || tile.GetObject() == MP2::OBJ_HEROES );
1895 }
1896 
PresentBoat(void) const1897 bool Castle::PresentBoat( void ) const
1898 {
1899     // 2 cell down
1900     if ( Maps::isValidAbsPoint( center.x, center.y + 2 ) ) {
1901         const s32 index = Maps::GetIndexFromAbsPoint( center.x, center.y + 2 );
1902         const s32 max = world.w() * world.h();
1903 
1904         if ( index + 1 < max ) {
1905             const Maps::Tiles & left = world.GetTiles( index - 1 );
1906             const Maps::Tiles & right = world.GetTiles( index + 1 );
1907             const Maps::Tiles & middle = world.GetTiles( index );
1908 
1909             if ( TilePresentBoat( left ) || TilePresentBoat( right ) || TilePresentBoat( middle ) )
1910                 return true;
1911         }
1912     }
1913     return false;
1914 }
1915 
GetActualDwelling(u32 build) const1916 u32 Castle::GetActualDwelling( u32 build ) const
1917 {
1918     switch ( build ) {
1919     case DWELLING_MONSTER1:
1920     case DWELLING_UPGRADE2:
1921     case DWELLING_UPGRADE3:
1922     case DWELLING_UPGRADE4:
1923     case DWELLING_UPGRADE5:
1924     case DWELLING_UPGRADE7:
1925         return build;
1926     case DWELLING_MONSTER2:
1927         return building & DWELLING_UPGRADE2 ? DWELLING_UPGRADE2 : build;
1928     case DWELLING_MONSTER3:
1929         return building & DWELLING_UPGRADE3 ? DWELLING_UPGRADE3 : build;
1930     case DWELLING_MONSTER4:
1931         return building & DWELLING_UPGRADE4 ? DWELLING_UPGRADE4 : build;
1932     case DWELLING_MONSTER5:
1933         return building & DWELLING_UPGRADE5 ? DWELLING_UPGRADE5 : build;
1934     case DWELLING_MONSTER6:
1935         return building & DWELLING_UPGRADE7 ? DWELLING_UPGRADE7 : ( building & DWELLING_UPGRADE6 ? DWELLING_UPGRADE6 : build );
1936     case DWELLING_UPGRADE6:
1937         return building & DWELLING_UPGRADE7 ? DWELLING_UPGRADE7 : build;
1938     default:
1939         break;
1940     }
1941 
1942     return BUILD_NOTHING;
1943 }
1944 
GetUpgradeBuilding(u32 build) const1945 u32 Castle::GetUpgradeBuilding( u32 build ) const
1946 {
1947     switch ( build ) {
1948     case BUILD_TENT:
1949         return BUILD_CASTLE;
1950     case BUILD_MAGEGUILD1:
1951         return BUILD_MAGEGUILD2;
1952     case BUILD_MAGEGUILD2:
1953         return BUILD_MAGEGUILD3;
1954     case BUILD_MAGEGUILD3:
1955         return BUILD_MAGEGUILD4;
1956     case BUILD_MAGEGUILD4:
1957         return BUILD_MAGEGUILD5;
1958     default:
1959         break;
1960     }
1961 
1962     if ( Race::BARB == race ) {
1963         switch ( build ) {
1964         case DWELLING_MONSTER2:
1965             return DWELLING_UPGRADE2;
1966         case DWELLING_MONSTER4:
1967             return DWELLING_UPGRADE4;
1968         case DWELLING_MONSTER5:
1969             return DWELLING_UPGRADE5;
1970         default:
1971             break;
1972         }
1973     }
1974     else if ( Race::KNGT == race ) {
1975         switch ( build ) {
1976         case DWELLING_MONSTER2:
1977             return DWELLING_UPGRADE2;
1978         case DWELLING_MONSTER3:
1979             return DWELLING_UPGRADE3;
1980         case DWELLING_MONSTER4:
1981             return DWELLING_UPGRADE4;
1982         case DWELLING_MONSTER5:
1983             return DWELLING_UPGRADE5;
1984         case DWELLING_MONSTER6:
1985             return DWELLING_UPGRADE6;
1986         default:
1987             break;
1988         }
1989     }
1990     else if ( Race::NECR == race ) {
1991         switch ( build ) {
1992         case DWELLING_MONSTER2:
1993             return DWELLING_UPGRADE2;
1994         case DWELLING_MONSTER3:
1995             return DWELLING_UPGRADE3;
1996         case DWELLING_MONSTER4:
1997             return DWELLING_UPGRADE4;
1998         case DWELLING_MONSTER5:
1999             return DWELLING_UPGRADE5;
2000         default:
2001             break;
2002         }
2003     }
2004     else if ( Race::SORC == race ) {
2005         switch ( build ) {
2006         case DWELLING_MONSTER2:
2007             return DWELLING_UPGRADE2;
2008         case DWELLING_MONSTER3:
2009             return DWELLING_UPGRADE3;
2010         case DWELLING_MONSTER4:
2011             return DWELLING_UPGRADE4;
2012         default:
2013             break;
2014         }
2015     }
2016     else if ( Race::WRLK == race ) {
2017         switch ( build ) {
2018         case DWELLING_MONSTER4:
2019             return DWELLING_UPGRADE4;
2020         case DWELLING_MONSTER6:
2021             return isBuild( DWELLING_UPGRADE6 ) ? DWELLING_UPGRADE7 : DWELLING_UPGRADE6;
2022         default:
2023             break;
2024         }
2025     }
2026     else if ( Race::WZRD == race ) {
2027         switch ( build ) {
2028         case DWELLING_MONSTER3:
2029             return DWELLING_UPGRADE3;
2030         case DWELLING_MONSTER5:
2031             return DWELLING_UPGRADE5;
2032         case DWELLING_MONSTER6:
2033             return DWELLING_UPGRADE6;
2034         default:
2035             break;
2036         }
2037     }
2038 
2039     return build;
2040 }
2041 
PredicateIsCastle(const Castle * castle)2042 bool Castle::PredicateIsCastle( const Castle * castle )
2043 {
2044     return castle && castle->isCastle();
2045 }
2046 
PredicateIsTown(const Castle * castle)2047 bool Castle::PredicateIsTown( const Castle * castle )
2048 {
2049     return castle && !castle->isCastle();
2050 }
2051 
PredicateIsBuildBuilding(const Castle * castle,const uint32_t building)2052 bool Castle::PredicateIsBuildBuilding( const Castle * castle, const uint32_t building )
2053 {
2054     return castle && castle->isBuild( building );
2055 }
2056 
String(void) const2057 std::string Castle::String( void ) const
2058 {
2059     std::ostringstream os;
2060     const CastleHeroes heroes = GetHeroes();
2061     const Heroes * hero = nullptr;
2062 
2063     os << "name and type   : " << name << " (" << Race::String( race ) << ")" << std::endl
2064        << "color           : " << Color::String( GetColor() ) << std::endl
2065        << "dwellings       : ";
2066 
2067     for ( uint32_t level = 0; level < 7; ++level ) {
2068         // there is no dwelling 7
2069         if ( level != 6 && isBuild( DWELLING_MONSTER1 << level ) )
2070             os << level + 1;
2071 
2072         if ( level > 0 && isBuild( DWELLING_UPGRADE2 << ( level - 1 ) ) )
2073             os << "U, ";
2074         else
2075             os << ", ";
2076     }
2077     os << std::endl;
2078 
2079     os << "buildings       : " << CountBuildings() << " (mage guild: " << GetLevelMageGuild() << ")" << std::endl
2080        << "coast/has boat  : " << ( HaveNearlySea() ? "yes" : "no" ) << " / " << ( PresentBoat() ? "yes" : "no" ) << std::endl
2081        << "is castle       : " << ( isCastle() ? "yes" : "no" ) << " (" << getBuildingValue() << ")" << std::endl
2082        << "army            : " << army.String() << std::endl;
2083 
2084     if ( nullptr != ( hero = heroes.Guard() ) ) {
2085         os << "army guard      : " << hero->GetArmy().String() << std::endl;
2086     }
2087 
2088     if ( nullptr != ( hero = heroes.Guest() ) ) {
2089         os << "army guest      : " << hero->GetArmy().String() << std::endl;
2090     }
2091 
2092     return os.str();
2093 }
2094 
GetAttackModificator(const std::string *) const2095 int Castle::GetAttackModificator( const std::string * ) const
2096 {
2097     return 0;
2098 }
2099 
GetDefenseModificator(const std::string *) const2100 int Castle::GetDefenseModificator( const std::string * ) const
2101 {
2102     return 0;
2103 }
2104 
GetPowerModificator(std::string * strs) const2105 int Castle::GetPowerModificator( std::string * strs ) const
2106 {
2107     int result = 0;
2108 
2109     if ( Race::NECR == race && isBuild( BUILD_SPEC ) ) {
2110         const int mod = 2;
2111         result += mod;
2112         if ( strs ) {
2113             strs->append( GetStringBuilding( BUILD_SPEC, race ) );
2114             StringAppendModifiers( *strs, mod );
2115         }
2116     }
2117 
2118     return result;
2119 }
2120 
GetKnowledgeModificator(const std::string *) const2121 int Castle::GetKnowledgeModificator( const std::string * ) const
2122 {
2123     return 0;
2124 }
2125 
GetMoraleModificator(std::string * strs) const2126 int Castle::GetMoraleModificator( std::string * strs ) const
2127 {
2128     int result = Morale::NORMAL;
2129 
2130     // and tavern
2131     if ( isBuild( BUILD_TAVERN ) ) {
2132         const int mod = 1;
2133         result += mod;
2134         if ( strs ) {
2135             strs->append( GetStringBuilding( BUILD_TAVERN, race ) );
2136             StringAppendModifiers( *strs, mod );
2137             strs->append( "\n" );
2138         }
2139     }
2140 
2141     // and barbarian coliseum
2142     if ( Race::BARB == race && isBuild( BUILD_SPEC ) ) {
2143         const int mod = 2;
2144         result += mod;
2145         if ( strs ) {
2146             strs->append( GetStringBuilding( BUILD_SPEC, race ) );
2147             StringAppendModifiers( *strs, mod );
2148             strs->append( "\n" );
2149         }
2150     }
2151 
2152     return result;
2153 }
2154 
GetLuckModificator(std::string * strs) const2155 int Castle::GetLuckModificator( std::string * strs ) const
2156 {
2157     int result = Luck::NORMAL;
2158 
2159     if ( Race::SORC == race && isBuild( BUILD_SPEC ) ) {
2160         const int mod = 2;
2161         result += mod;
2162         if ( strs ) {
2163             strs->append( Castle::GetStringBuilding( BUILD_SPEC, race ) );
2164             StringAppendModifiers( *strs, mod );
2165             strs->append( "\n" );
2166         }
2167     }
2168 
2169     return result;
2170 }
2171 
GetArmy(void) const2172 const Army & Castle::GetArmy( void ) const
2173 {
2174     const CastleHeroes heroes = world.GetHeroes( *this );
2175     return heroes.Guard() ? heroes.Guard()->GetArmy() : army;
2176 }
2177 
GetArmy(void)2178 Army & Castle::GetArmy( void )
2179 {
2180     CastleHeroes heroes = world.GetHeroes( *this );
2181     return heroes.Guard() ? heroes.Guard()->GetArmy() : army;
2182 }
2183 
GetActualArmy(void) const2184 const Army & Castle::GetActualArmy( void ) const
2185 {
2186     CastleHeroes heroes = world.GetHeroes( *this );
2187     const Heroes * hero = heroes.GuardFirst();
2188     return hero ? hero->GetArmy() : army;
2189 }
2190 
GetActualArmy(void)2191 Army & Castle::GetActualArmy( void )
2192 {
2193     CastleHeroes heroes = world.GetHeroes( *this );
2194     Heroes * hero = heroes.GuardFirst();
2195     return hero ? hero->GetArmy() : army;
2196 }
2197 
GetGarrisonStrength(const Heroes * attackingHero) const2198 double Castle::GetGarrisonStrength( const Heroes * attackingHero ) const
2199 {
2200     double totalStrength = 0;
2201 
2202     CastleHeroes heroes = world.GetHeroes( *this );
2203     if ( heroes.Guest() ) {
2204         totalStrength += heroes.Guest()->GetArmy().GetStrength();
2205     }
2206     if ( Settings::Get().ExtCastleAllowGuardians() && heroes.Guard() ) {
2207         totalStrength += heroes.Guard()->GetArmy().GetStrength();
2208     }
2209     else {
2210         totalStrength += army.GetStrength();
2211     }
2212 
2213     // Add castle bonus if there are any troops defending it
2214     if ( isCastle() && totalStrength > 1 ) {
2215         const Battle::Tower tower( *this, Battle::TWR_CENTER, Rand::DeterministicRandomGenerator( 0 ), 0 );
2216         const double towerStr = tower.GetStrengthWithBonus( tower.GetBonus(), 0 );
2217 
2218         totalStrength += towerStr;
2219         if ( isBuild( BUILD_LEFTTURRET ) ) {
2220             totalStrength += towerStr / 2;
2221         }
2222         if ( isBuild( BUILD_RIGHTTURRET ) ) {
2223             totalStrength += towerStr / 2;
2224         }
2225 
2226         if ( attackingHero && ( !attackingHero->GetArmy().isMeleeDominantArmy() || attackingHero->HasSecondarySkill( Skill::Secondary::BALLISTICS ) ) ) {
2227             totalStrength *= isBuild( BUILD_MOAT ) ? 1.2 : 1.15;
2228         }
2229         else {
2230             // heavy penalty if no ballistics skill and army is melee infantry based
2231             totalStrength *= isBuild( BUILD_MOAT ) ? 1.45 : 1.25;
2232         }
2233     }
2234     return totalStrength;
2235 }
2236 
AllowBuyBoat(void) const2237 bool Castle::AllowBuyBoat( void ) const
2238 {
2239     // check payment and present other boat
2240     return ( HaveNearlySea() && isBuild( BUILD_SHIPYARD ) && GetKingdom().AllowPayment( PaymentConditions::BuyBoat() ) && !PresentBoat() );
2241 }
2242 
BuyBoat(void) const2243 bool Castle::BuyBoat( void ) const
2244 {
2245     if ( !AllowBuyBoat() )
2246         return false;
2247     if ( isControlHuman() )
2248         AGG::PlaySound( M82::BUILDTWN );
2249 
2250     if ( !Maps::isValidAbsPoint( center.x, center.y + 2 ) )
2251         return false;
2252 
2253     const s32 index = Maps::GetIndexFromAbsPoint( center.x, center.y + 2 );
2254     Maps::Tiles & left = world.GetTiles( index - 1 );
2255     Maps::Tiles & right = world.GetTiles( index + 1 );
2256     Maps::Tiles & middle = world.GetTiles( index );
2257     Kingdom & kingdom = GetKingdom();
2258 
2259     if ( MP2::OBJ_ZERO == left.GetObject() && left.isWater() ) {
2260         kingdom.OddFundsResource( PaymentConditions::BuyBoat() );
2261 
2262         left.setBoat( Direction::RIGHT );
2263     }
2264     else if ( MP2::OBJ_ZERO == right.GetObject() && right.isWater() ) {
2265         kingdom.OddFundsResource( PaymentConditions::BuyBoat() );
2266 
2267         right.setBoat( Direction::RIGHT );
2268     }
2269     else if ( MP2::OBJ_ZERO == middle.GetObject() && middle.isWater() ) {
2270         kingdom.OddFundsResource( PaymentConditions::BuyBoat() );
2271 
2272         middle.setBoat( Direction::RIGHT );
2273     }
2274 
2275     return true;
2276 }
2277 
GetRace(void) const2278 int Castle::GetRace( void ) const
2279 {
2280     return race;
2281 }
2282 
GetName(void) const2283 const std::string & Castle::GetName( void ) const
2284 {
2285     return name;
2286 }
2287 
setName(const std::set<std::string> & usedNames)2288 void Castle::setName( const std::set<std::string> & usedNames )
2289 {
2290     assert( name.empty() );
2291 
2292     std::vector<const char *> shuffledCastleNames( defaultCastleNames.begin(), defaultCastleNames.end() );
2293 
2294     Rand::Shuffle( shuffledCastleNames );
2295 
2296     for ( const char * originalName : shuffledCastleNames ) {
2297         const char * translatedCastleName = _( originalName );
2298         if ( usedNames.count( translatedCastleName ) < 1 ) {
2299             name = translatedCastleName;
2300             return;
2301         }
2302     }
2303 
2304     // How is it possible that we're out of castle names?
2305     assert( 0 );
2306 }
2307 
GetControl(void) const2308 int Castle::GetControl( void ) const
2309 {
2310     /* gray towns: ai control */
2311     return GetColor() & Color::ALL ? GetKingdom().GetControl() : CONTROL_AI;
2312 }
2313 
isBuild(u32 bd) const2314 bool Castle::isBuild( u32 bd ) const
2315 {
2316     return ( building & bd ) != 0;
2317 }
2318 
isNecromancyShrineBuild(void) const2319 bool Castle::isNecromancyShrineBuild( void ) const
2320 {
2321     return race == Race::NECR && ( BUILD_SHRINE & building );
2322 }
2323 
GetGrownWell(void)2324 u32 Castle::GetGrownWell( void )
2325 {
2326     return GameStatic::GetCastleGrownWell();
2327 }
2328 
GetGrownWel2(void)2329 u32 Castle::GetGrownWel2( void )
2330 {
2331     return GameStatic::GetCastleGrownWel2();
2332 }
2333 
GetGrownWeekOf()2334 u32 Castle::GetGrownWeekOf()
2335 {
2336     return GameStatic::GetCastleGrownWeekOf();
2337 }
2338 
GetGrownMonthOf(void)2339 u32 Castle::GetGrownMonthOf( void )
2340 {
2341     return GameStatic::GetCastleGrownMonthOf();
2342 }
2343 
Scoute(void) const2344 void Castle::Scoute( void ) const
2345 {
2346     Maps::ClearFog( GetIndex(), Game::GetViewDistance( Game::VIEW_CASTLE ), GetColor() );
2347 }
2348 
JoinRNDArmy(void)2349 void Castle::JoinRNDArmy( void )
2350 {
2351     const uint32_t timeModifier = world.CountDay() / 10;
2352     const uint32_t reinforcementQuality = Rand::Get( 1, 15 ) + timeModifier;
2353 
2354     uint32_t count = timeModifier / 2;
2355     uint32_t dwellingType = DWELLING_MONSTER1;
2356 
2357     if ( reinforcementQuality > 15 ) {
2358         dwellingType = DWELLING_MONSTER5;
2359         count += 1;
2360     }
2361     else if ( reinforcementQuality > 13 ) {
2362         dwellingType = DWELLING_MONSTER4;
2363         count += Rand::Get( 1, 3 );
2364     }
2365     else if ( reinforcementQuality > 10 ) {
2366         dwellingType = DWELLING_MONSTER3;
2367         count += Rand::Get( 3, 5 );
2368     }
2369     else if ( reinforcementQuality > 5 ) {
2370         dwellingType = DWELLING_MONSTER2;
2371         count += Rand::Get( 5, 7 );
2372     }
2373     else {
2374         count += Rand::Get( 8, 15 );
2375     }
2376 
2377     army.JoinTroop( Monster( race, dwellingType ), count );
2378 }
2379 
ActionPreBattle(void)2380 void Castle::ActionPreBattle( void )
2381 {
2382     CastleHeroes heroes = world.GetHeroes( *this );
2383     Heroes * hero = heroes.GuardFirst();
2384     if ( hero && army.isValid() )
2385         hero->GetArmy().JoinStrongestFromArmy( army );
2386 
2387     if ( isControlAI() )
2388         AI::Get().CastlePreBattle( *this );
2389 }
2390 
ActionAfterBattle(bool attacker_wins)2391 void Castle::ActionAfterBattle( bool attacker_wins )
2392 {
2393     if ( attacker_wins ) {
2394         army.Clean();
2395         ResetModes( CUSTOMARMY );
2396     }
2397 
2398     if ( isControlAI() )
2399         AI::Get().CastleAfterBattle( *this, attacker_wins );
2400 }
2401 
GetFirstCastle(void) const2402 Castle * VecCastles::GetFirstCastle( void ) const
2403 {
2404     const_iterator it = std::find_if( begin(), end(), []( const Castle * castle ) { return castle->isCastle(); } );
2405     return end() != it ? *it : nullptr;
2406 }
2407 
SortByBuildingValue()2408 void VecCastles::SortByBuildingValue()
2409 {
2410     std::sort( begin(), end(), []( const Castle * left, const Castle * right ) {
2411         if ( left && right )
2412             return left->getBuildingValue() > right->getBuildingValue();
2413         return right == nullptr;
2414     } );
2415 }
2416 
ChangeColors(int col1,int col2)2417 void VecCastles::ChangeColors( int col1, int col2 )
2418 {
2419     for ( iterator it = begin(); it != end(); ++it )
2420         if ( ( *it )->GetColor() == col1 )
2421             ( *it )->ChangeColor( col2 );
2422 }
2423 
AllCastles()2424 AllCastles::AllCastles()
2425 {
2426     // reserve memory
2427     _castles.reserve( maximumCastles );
2428 }
2429 
~AllCastles()2430 AllCastles::~AllCastles()
2431 {
2432     Clear();
2433 }
2434 
Init(void)2435 void AllCastles::Init( void )
2436 {
2437     Clear();
2438 }
2439 
Clear(void)2440 void AllCastles::Clear( void )
2441 {
2442     for ( auto it = begin(); it != end(); ++it )
2443         delete *it;
2444     _castles.clear();
2445     _castleTiles.clear();
2446 }
2447 
AddCastle(Castle * castle)2448 void AllCastles::AddCastle( Castle * castle )
2449 {
2450     _castles.push_back( castle );
2451 
2452     /* Register position of all castle elements on the map
2453     Castle element positions are:
2454                 +
2455               +++++
2456               +++++
2457               ++X++
2458               ++ ++
2459 
2460      where
2461      X is the main castle position
2462      + are tiles that are considered part of the castle for the Get() method
2463     */
2464 
2465     const size_t id = _castles.size() - 1;
2466     fheroes2::Point temp( castle->GetCenter().x, castle->GetCenter().y );
2467 
2468     for ( int32_t y = -2; y <= 2; ++y ) {
2469         for ( int32_t x = -2; x <= 2; ++x ) {
2470             _castleTiles.emplace( temp + fheroes2::Point( x, y ), id );
2471         }
2472     }
2473 
2474     _castleTiles.emplace( temp + fheroes2::Point( 0, -3 ), id );
2475 }
2476 
Get(const fheroes2::Point & position) const2477 Castle * AllCastles::Get( const fheroes2::Point & position ) const
2478 {
2479     auto iter = _castleTiles.find( position );
2480     if ( iter == _castleTiles.end() )
2481         return nullptr;
2482 
2483     return _castles[iter->second];
2484 }
2485 
Scoute(int colors) const2486 void AllCastles::Scoute( int colors ) const
2487 {
2488     for ( auto it = begin(); it != end(); ++it )
2489         if ( colors & ( *it )->GetColor() )
2490             ( *it )->Scoute();
2491 }
2492 
2493 /* pack castle */
operator <<(StreamBase & msg,const Castle & castle)2494 StreamBase & operator<<( StreamBase & msg, const Castle & castle )
2495 {
2496     const ColorBase & color = castle;
2497 
2498     msg << static_cast<const MapPosition &>( castle ) << castle.modes << castle.race << castle.building << castle.captain << color << castle.name << castle.mageguild
2499         << static_cast<u32>( CASTLEMAXMONSTER );
2500 
2501     for ( u32 ii = 0; ii < CASTLEMAXMONSTER; ++ii )
2502         msg << castle.dwelling[ii];
2503 
2504     return msg << castle.army;
2505 }
2506 
2507 /* unpack castle */
operator >>(StreamBase & msg,Castle & castle)2508 StreamBase & operator>>( StreamBase & msg, Castle & castle )
2509 {
2510     ColorBase & color = castle;
2511     u32 dwellingcount;
2512 
2513     msg >> static_cast<MapPosition &>( castle ) >> castle.modes >> castle.race >> castle.building >> castle.captain >> color >> castle.name >> castle.mageguild;
2514 
2515     msg >> dwellingcount;
2516     for ( u32 ii = 0; ii < dwellingcount; ++ii )
2517         msg >> castle.dwelling[ii];
2518 
2519     msg >> castle.army;
2520     castle.army.SetCommander( &castle.captain );
2521 
2522     return msg;
2523 }
2524 
operator <<(StreamBase & msg,const VecCastles & castles)2525 StreamBase & operator<<( StreamBase & msg, const VecCastles & castles )
2526 {
2527     msg << static_cast<u32>( castles.size() );
2528 
2529     for ( auto it = castles.begin(); it != castles.end(); ++it )
2530         msg << ( *it ? ( *it )->GetIndex() : static_cast<s32>( -1 ) );
2531 
2532     return msg;
2533 }
2534 
operator >>(StreamBase & msg,VecCastles & castles)2535 StreamBase & operator>>( StreamBase & msg, VecCastles & castles )
2536 {
2537     s32 index;
2538     u32 size;
2539     msg >> size;
2540 
2541     castles.resize( size, nullptr );
2542 
2543     for ( auto it = castles.begin(); it != castles.end(); ++it ) {
2544         msg >> index;
2545         *it = ( index < 0 ? nullptr : world.getCastleEntrance( Maps::GetPoint( index ) ) );
2546         assert( *it != nullptr );
2547     }
2548 
2549     return msg;
2550 }
2551 
operator <<(StreamBase & msg,const AllCastles & castles)2552 StreamBase & operator<<( StreamBase & msg, const AllCastles & castles )
2553 {
2554     msg << static_cast<u32>( castles.Size() );
2555 
2556     for ( const auto & castle : castles )
2557         msg << *castle;
2558 
2559     return msg;
2560 }
2561 
operator >>(StreamBase & msg,AllCastles & castles)2562 StreamBase & operator>>( StreamBase & msg, AllCastles & castles )
2563 {
2564     uint32_t size;
2565     msg >> size;
2566 
2567     castles.Clear();
2568 
2569     for ( uint32_t i = 0; i < size; ++i ) {
2570         Castle * castle = new Castle();
2571         msg >> *castle;
2572         castles.AddCastle( castle );
2573     }
2574 
2575     return msg;
2576 }
2577 
SwapCastleHeroes(CastleHeroes & heroes)2578 void Castle::SwapCastleHeroes( CastleHeroes & heroes )
2579 {
2580     if ( heroes.Guest() && heroes.Guard() ) {
2581         heroes.Guest()->SetModes( Heroes::GUARDIAN );
2582         heroes.Guest()->ResetModes( Heroes::SLEEPER );
2583         heroes.Guard()->ResetModes( Heroes::GUARDIAN );
2584         heroes.Swap();
2585 
2586         world.GetTiles( center.x, center.y ).SetHeroes( nullptr );
2587 
2588         fheroes2::Point position( heroes.Guard()->GetCenter() );
2589         position.y -= 1;
2590         heroes.Guard()->SetCenter( position );
2591         heroes.Guard()->GetPath().Reset();
2592 
2593         position = heroes.Guest()->GetCenter();
2594         position.y += 1;
2595         heroes.Guest()->SetCenter( position );
2596         heroes.Guest()->GetPath().Reset();
2597 
2598         world.GetTiles( center.x, center.y ).SetHeroes( heroes.Guest() );
2599     }
2600     else if ( heroes.Guest() && !heroes.Guard() ) {
2601         heroes.Guest()->SetModes( Heroes::GUARDIAN );
2602         heroes.Guest()->ResetModes( Heroes::SLEEPER );
2603         heroes.Swap();
2604         heroes.Guard()->GetArmy().JoinTroops( army );
2605 
2606         world.GetTiles( center.x, center.y ).SetHeroes( nullptr );
2607 
2608         fheroes2::Point position( heroes.Guard()->GetCenter() );
2609         position.y -= 1;
2610         heroes.Guard()->SetCenter( position );
2611         heroes.Guard()->GetPath().Reset();
2612     }
2613     else if ( !heroes.Guest() && heroes.Guard() ) {
2614         heroes.Guard()->ResetModes( Heroes::GUARDIAN );
2615         heroes.Swap();
2616 
2617         fheroes2::Point position( heroes.Guest()->GetCenter() );
2618         position.y += 1;
2619         heroes.Guest()->SetCenter( position );
2620         heroes.Guest()->GetPath().Reset();
2621 
2622         world.GetTiles( center.x, center.y ).SetHeroes( heroes.Guest() );
2623     }
2624 }
2625 
GetStringBuilding(u32 build) const2626 std::string Castle::GetStringBuilding( u32 build ) const
2627 {
2628     return GetStringBuilding( build, GetRace() );
2629 }
2630 
GetDescriptionBuilding(u32 build) const2631 std::string Castle::GetDescriptionBuilding( u32 build ) const
2632 {
2633     std::string res = GetDescriptionBuilding( build, GetRace() );
2634 
2635     switch ( build ) {
2636     case BUILD_WELL:
2637         StringReplace( res, "%{count}", GetGrownWell() );
2638         break;
2639 
2640     case BUILD_WEL2:
2641         StringReplace( res, "%{count}", GetGrownWel2() );
2642         break;
2643 
2644     case BUILD_CASTLE: {
2645         StringReplace( res, "%{count}", ProfitConditions::FromBuilding( BUILD_CASTLE, race ).gold );
2646 
2647         if ( isBuild( BUILD_CASTLE ) ) {
2648             res.append( "\n \n" );
2649             res.append( Battle::Tower::GetInfo( *this ) );
2650         }
2651 
2652         if ( isBuild( BUILD_MOAT ) ) {
2653             res.append( "\n \n" );
2654             res.append( Battle::Board::GetMoatInfo() );
2655         }
2656         break;
2657     }
2658 
2659     case BUILD_SPEC:
2660     case BUILD_STATUE: {
2661         const payment_t profit = ProfitConditions::FromBuilding( build, GetRace() );
2662         StringReplace( res, "%{count}", profit.gold );
2663         break;
2664     }
2665 
2666     default:
2667         break;
2668     }
2669 
2670     return res;
2671 }
2672