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