2013-01-12 13:32:03 +03:00
/*
* CObjectHandler . cpp , part of VCMI engine
*
* Authors : listed in file AUTHORS in main folder
*
* License : GNU General Public License v2 .0 or later
* Full text of license available in license . txt file , in main folder
*
*/
2011-12-14 00:23:17 +03:00
# include "StdInc.h"
2007-06-12 12:33:20 +03:00
# include "CObjectHandler.h"
2011-12-14 00:23:17 +03:00
2008-06-13 11:16:51 +03:00
# include "CDefObjInfoHandler.h"
2008-11-28 03:36:34 +02:00
# include "CGeneralTextHandler.h"
2007-10-26 20:55:33 +03:00
# include "CDefObjInfoHandler.h"
2007-11-19 00:58:28 +02:00
# include "CHeroHandler.h"
2008-11-11 17:17:58 +02:00
# include "CSpellHandler.h"
2012-08-11 12:06:23 +03:00
# include "CModHandler.h"
2010-12-20 23:22:53 +02:00
# include "../client/CSoundBase.h"
2008-04-14 20:45:01 +03:00
# include "CTownHandler.h"
2010-07-16 17:22:18 +03:00
# include "CCreatureHandler.h"
2010-12-20 23:22:53 +02:00
# include "VCMI_Lib.h"
# include "IGameCallback.h"
# include "CGameState.h"
# include "NetPacks.h"
2011-12-14 00:23:17 +03:00
# include "StartInfo.h"
2013-04-07 13:48:07 +03:00
# include "mapping/CMap.h"
2009-09-17 13:47:47 +03:00
# include <SDL_stdinc.h>
2011-08-26 23:32:05 +03:00
# include "CBuildingHandler.h"
2012-08-02 14:03:26 +03:00
# include "JsonNode.h"
2013-07-28 17:49:50 +03:00
# include "filesystem/Filesystem.h"
2011-02-22 11:47:25 +02:00
2009-07-26 06:33:13 +03:00
using namespace boost : : assign ;
2008-12-22 19:48:41 +02:00
2012-02-21 17:08:42 +03:00
// It looks that we can't rely on shadowCoverage correctness (Mantis #866). This may result
// in notable performance decrease (SDL blit with custom alpha blit) not notable on my system (Ivan)
# define USE_COVERAGE_MAP 0
2013-02-16 17:03:47 +03:00
std : : map < Obj , std : : map < int , std : : vector < ObjectInstanceID > > > CGTeleport : : objs ;
2013-02-14 02:55:42 +03:00
std : : vector < std : : pair < ObjectInstanceID , ObjectInstanceID > > CGTeleport : : gates ;
2013-06-26 14:18:27 +03:00
IGameCallback * IObjectInterface : : cb = nullptr ;
extern std : : minstd_rand ran ;
2013-03-03 20:06:03 +03:00
std : : map < PlayerColor , std : : set < ui8 > > CGKeys : : playerKeyMap ;
2013-02-14 02:55:42 +03:00
std : : map < si32 , std : : vector < ObjectInstanceID > > CGMagi : : eyelist ;
2010-02-10 04:56:00 +02:00
ui8 CGObelisk : : obeliskCount ; //how many obelisks are on map
2013-03-03 20:06:03 +03:00
std : : map < TeamID , ui8 > CGObelisk : : visited ; //map: team_id => how many obelisks has been visited
2010-02-10 04:56:00 +02:00
2010-06-26 19:02:10 +03:00
std : : vector < const CArtifact * > CGTownInstance : : merchantArtifacts ;
2010-07-20 17:08:13 +03:00
std : : vector < int > CGTownInstance : : universitySkills ;
2010-06-26 19:02:10 +03:00
2013-01-12 13:32:03 +03:00
///helpers
2013-02-14 02:55:42 +03:00
static void openWindow ( const OpenWindow : : EWindow type , const int id1 , const int id2 = - 1 )
2013-01-12 13:32:03 +03:00
{
OpenWindow ow ;
ow . window = type ;
ow . id1 = id1 ;
ow . id2 = id2 ;
IObjectInterface : : cb - > sendAndApply ( & ow ) ;
}
2013-03-03 20:06:03 +03:00
static void showInfoDialog ( const PlayerColor playerID , const ui32 txtID , const ui16 soundID )
2013-01-12 13:32:03 +03:00
{
InfoWindow iw ;
iw . soundID = soundID ;
iw . player = playerID ;
iw . text . addTxt ( MetaString : : ADVOB_TXT , txtID ) ;
IObjectInterface : : cb - > sendAndApply ( & iw ) ;
}
2013-04-22 22:51:22 +03:00
/*static void showInfoDialog(const ObjectInstanceID heroID, const ui32 txtID, const ui16 soundID)
2013-01-12 13:32:03 +03:00
{
2013-03-03 20:06:03 +03:00
const PlayerColor playerID = IObjectInterface : : cb - > getOwner ( heroID ) ;
2013-01-12 13:32:03 +03:00
showInfoDialog ( playerID , txtID , soundID ) ;
2013-04-22 22:51:22 +03:00
} */
2013-01-12 13:32:03 +03:00
static void showInfoDialog ( const CGHeroInstance * h , const ui32 txtID , const ui16 soundID )
{
2013-03-03 20:06:03 +03:00
const PlayerColor playerID = h - > getOwner ( ) ;
2013-01-12 13:32:03 +03:00
showInfoDialog ( playerID , txtID , soundID ) ;
}
2013-01-13 15:40:24 +03:00
static std : : string & visitedTxt ( const bool visited )
{
int id = visited ? 352 : 353 ;
return VLC - > generaltexth - > allTexts [ id ] ;
}
2013-01-12 13:32:03 +03:00
///IObjectInterface
2012-07-19 21:52:44 +03:00
void IObjectInterface : : onHeroVisit ( const CGHeroInstance * h ) const
2012-09-15 22:16:16 +03:00
{ }
2008-12-22 19:48:41 +02:00
2012-07-19 21:52:44 +03:00
void IObjectInterface : : onHeroLeave ( const CGHeroInstance * h ) const
2012-09-15 22:16:16 +03:00
{ }
2008-12-22 19:48:41 +02:00
2008-12-27 03:01:59 +02:00
void IObjectInterface : : newTurn ( ) const
2012-09-15 22:16:16 +03:00
{ }
2008-12-22 19:48:41 +02:00
IObjectInterface : : ~ IObjectInterface ( )
{ }
IObjectInterface : : IObjectInterface ( )
{ }
void IObjectInterface : : initObj ( )
{ }
2009-02-20 14:39:27 +02:00
void IObjectInterface : : setProperty ( ui8 what , ui32 val )
{ }
2013-03-03 20:06:03 +03:00
bool IObjectInterface : : wasVisited ( PlayerColor player ) const
2012-03-14 16:02:38 +03:00
{
return false ;
}
bool IObjectInterface : : wasVisited ( const CGHeroInstance * h ) const
{
return false ;
}
2009-09-07 05:29:44 +03:00
void IObjectInterface : : postInit ( )
{ }
void IObjectInterface : : preInit ( )
{ }
2013-04-20 14:34:01 +03:00
void IObjectInterface : : battleFinished ( const CGHeroInstance * hero , const BattleResult & result ) const
{
}
void IObjectInterface : : blockingDialogAnswered ( const CGHeroInstance * hero , ui32 answer ) const
{
}
void IObjectInterface : : garrisonDialogClosed ( const CGHeroInstance * hero ) const
{
}
2013-05-28 00:46:04 +03:00
void IObjectInterface : : heroLevelUpDone ( const CGHeroInstance * hero ) const
{
}
2009-03-14 19:19:53 +02:00
void CPlayersVisited : : setPropertyDer ( ui8 what , ui32 val )
{
if ( what = = 10 )
2013-03-03 20:06:03 +03:00
players . insert ( PlayerColor ( val ) ) ;
2009-03-14 19:19:53 +02:00
}
2013-03-03 20:06:03 +03:00
bool CPlayersVisited : : wasVisited ( PlayerColor player ) const
2009-03-14 19:19:53 +02:00
{
return vstd : : contains ( players , player ) ;
}
2013-03-03 20:06:03 +03:00
bool CPlayersVisited : : wasVisited ( TeamID team ) const
{
2013-06-29 16:05:48 +03:00
for ( auto i : players )
2013-03-03 20:06:03 +03:00
{
if ( cb - > getPlayer ( i ) - > team = = team )
return true ;
}
return false ;
}
2011-09-03 21:32:37 +03:00
// Bank helper. Find the creature ID and their number, and store the
// result in storage (either guards or reward creatures).
2013-02-11 02:24:57 +03:00
static void readCreatures ( const JsonNode & creature , std : : vector < std : : pair < CreatureID , ui32 > > & storage )
2009-08-20 13:07:23 +03:00
{
2013-02-11 02:24:57 +03:00
std : : pair < CreatureID , si32 > creInfo = std : : make_pair ( CreatureID : : NONE , 0 ) ;
2011-09-03 21:32:37 +03:00
2012-01-19 17:33:22 +03:00
creInfo . second = creature [ " number " ] . Float ( ) ;
2013-02-11 02:24:57 +03:00
creInfo . first = CreatureID ( ( si32 ) creature [ " id " ] . Float ( ) ) ;
2012-01-23 03:02:10 +03:00
storage . push_back ( creInfo ) ;
2009-08-20 13:07:23 +03:00
}
2010-08-18 16:42:46 +03:00
2011-09-03 21:32:37 +03:00
// Bank helper. Process a bank level.
static void readBankLevel ( const JsonNode & level , BankConfig & bc )
{
int idx ;
2010-08-18 16:42:46 +03:00
2011-09-03 21:32:37 +03:00
bc . chance = level [ " chance " ] . Float ( ) ;
2010-08-18 16:42:46 +03:00
2013-06-29 16:05:48 +03:00
for ( const JsonNode & creature : level [ " guards " ] . Vector ( ) )
2011-09-03 21:32:37 +03:00
{
readCreatures ( creature , bc . guards ) ;
}
2010-08-18 16:42:46 +03:00
2011-09-03 21:32:37 +03:00
bc . upgradeChance = level [ " upgrade_chance " ] . Float ( ) ;
bc . combatValue = level [ " combat_value " ] . Float ( ) ;
2010-08-18 16:42:46 +03:00
2011-12-14 00:23:17 +03:00
bc . resources . resize ( GameConstants : : RESOURCE_QUANTITY ) ;
2011-09-03 21:32:37 +03:00
idx = 0 ;
2013-06-29 16:05:48 +03:00
for ( const JsonNode & resource : level [ " reward_resources " ] . Vector ( ) )
2010-08-18 16:42:46 +03:00
{
2012-04-08 05:14:20 +03:00
bc . resources [ idx ] = resource . Float ( ) ;
2011-09-03 21:32:37 +03:00
idx + + ;
}
2013-06-29 16:05:48 +03:00
for ( const JsonNode & creature : level [ " reward_creatures " ] . Vector ( ) )
2011-09-03 21:32:37 +03:00
{
readCreatures ( creature , bc . creatures ) ;
2010-08-18 16:42:46 +03:00
}
bc . artifacts . resize ( 4 ) ;
2011-09-03 21:32:37 +03:00
idx = 0 ;
2013-06-29 16:05:48 +03:00
for ( const JsonNode & artifact : level [ " reward_artifacts " ] . Vector ( ) )
2010-08-18 16:42:46 +03:00
{
2011-09-03 21:32:37 +03:00
bc . artifacts [ idx ] = artifact . Float ( ) ;
idx + + ;
2010-08-18 16:42:46 +03:00
}
2011-09-03 21:32:37 +03:00
bc . value = level [ " value " ] . Float ( ) ;
bc . rewardDifficulty = level [ " profitability " ] . Float ( ) ;
bc . easiest = level [ " easiest " ] . Float ( ) ;
2010-08-18 16:42:46 +03:00
}
2009-08-20 13:07:23 +03:00
2013-04-21 15:49:26 +03:00
CObjectHandler : : CObjectHandler ( )
2007-06-11 20:21:27 +03:00
{
2013-04-09 17:31:36 +03:00
logGlobal - > traceStream ( ) < < " \t \t Reading cregens " ;
2010-05-18 10:01:54 +03:00
2012-08-02 14:03:26 +03:00
const JsonNode config ( ResourceID ( " config/dwellings.json " ) ) ;
2013-06-29 16:05:48 +03:00
for ( const JsonNode & dwelling : config [ " dwellings " ] . Vector ( ) )
2011-09-03 17:14:43 +03:00
{
2013-02-11 02:24:57 +03:00
cregens [ dwelling [ " dwelling " ] . Float ( ) ] = CreatureID ( ( si32 ) dwelling [ " creature " ] . Float ( ) ) ;
2011-09-03 17:14:43 +03:00
}
2013-04-09 17:31:36 +03:00
logGlobal - > traceStream ( ) < < " \t \t Done loading cregens! " ;
2010-05-18 10:01:54 +03:00
2013-04-09 17:31:36 +03:00
logGlobal - > traceStream ( ) < < " \t \t Reading resources prices " ;
2012-08-02 14:03:26 +03:00
const JsonNode config2 ( ResourceID ( " config/resources.json " ) ) ;
2013-06-29 16:05:48 +03:00
for ( const JsonNode & price : config2 [ " resources_prices " ] . Vector ( ) )
2011-09-03 17:14:43 +03:00
{
2011-09-03 17:26:39 +03:00
resVals . push_back ( price . Float ( ) ) ;
2008-02-05 05:56:45 +02:00
}
2013-04-09 17:31:36 +03:00
logGlobal - > traceStream ( ) < < " \t \t Done loading resource prices! " ;
2009-08-13 04:03:11 +03:00
2013-04-09 17:31:36 +03:00
logGlobal - > traceStream ( ) < < " \t \t Reading banks configs " ;
2012-08-02 14:03:26 +03:00
const JsonNode config3 ( ResourceID ( " config/bankconfig.json " ) ) ;
2011-09-03 21:32:37 +03:00
int bank_num = 0 ;
2013-06-29 16:05:48 +03:00
for ( const JsonNode & bank : config3 [ " banks " ] . Vector ( ) )
2009-09-25 12:57:13 +03:00
{
2011-09-03 21:32:37 +03:00
creBanksNames [ bank_num ] = bank [ " name " ] . String ( ) ;
2009-08-20 13:07:23 +03:00
2011-09-03 21:32:37 +03:00
int level_num = 0 ;
2013-06-29 16:05:48 +03:00
for ( const JsonNode & level : bank [ " levels " ] . Vector ( ) )
2009-08-20 13:07:23 +03:00
{
2011-09-03 21:32:37 +03:00
banksInfo [ bank_num ] . push_back ( new BankConfig ) ;
BankConfig & bc = * banksInfo [ bank_num ] . back ( ) ;
bc . level = level_num ;
readBankLevel ( level , bc ) ;
level_num + + ;
2009-08-20 13:07:23 +03:00
}
2011-09-03 21:32:37 +03:00
bank_num + + ;
2009-08-20 13:07:23 +03:00
}
2013-04-09 17:31:36 +03:00
logGlobal - > traceStream ( ) < < " \t \t Done loading banks configs " ;
2007-08-09 19:28:01 +03:00
}
2009-08-20 13:07:23 +03:00
2013-04-21 19:38:31 +03:00
CObjectHandler : : ~ CObjectHandler ( )
{
2013-06-29 16:05:48 +03:00
for ( auto & mapEntry : banksInfo )
2013-04-21 19:38:31 +03:00
{
2013-06-29 16:05:48 +03:00
for ( auto & vecEntry : mapEntry . second )
2013-04-21 19:38:31 +03:00
{
vecEntry . dellNull ( ) ;
}
}
}
2012-03-03 13:08:01 +03:00
int CObjectHandler : : bankObjToIndex ( const CGObjectInstance * obj )
{
2012-09-23 21:01:04 +03:00
switch ( obj - > ID ) //find appriopriate key
{
case Obj : : CREATURE_BANK :
return obj - > subID ;
case Obj : : DERELICT_SHIP :
return 8 ;
case Obj : : DRAGON_UTOPIA :
return 10 ;
case Obj : : CRYPT :
return 9 ;
case Obj : : SHIPWRECK :
return 7 ;
default :
2013-04-09 17:31:36 +03:00
logGlobal - > warnStream ( ) < < " Unrecognized Bank indetifier! " ;
2012-09-23 21:01:04 +03:00
return 0 ;
2012-03-03 13:08:01 +03:00
}
}
2013-03-03 20:06:03 +03:00
PlayerColor CGObjectInstance : : getOwner ( ) const
2007-10-27 22:38:48 +03:00
{
2007-11-19 00:58:28 +02:00
//if (state)
// return state->owner;
2008-08-02 18:08:03 +03:00
//else
2007-11-19 00:58:28 +02:00
return tempOwner ; //won't have owner
}
2013-02-19 01:37:22 +03:00
CGObjectInstance : : CGObjectInstance ( )
2008-12-22 19:48:41 +02:00
{
pos = int3 ( - 1 , - 1 , - 1 ) ;
//state = new CLuaObjectScript();
2013-02-07 20:34:50 +03:00
ID = Obj : : NO_OBJ ;
2013-02-14 02:55:42 +03:00
subID = - 1 ;
2013-06-26 14:18:27 +03:00
defInfo = nullptr ;
2013-03-03 20:06:03 +03:00
tempOwner = PlayerColor : : UNFLAGGABLE ;
2008-12-22 19:48:41 +02:00
blockVisit = false ;
}
CGObjectInstance : : ~ CGObjectInstance ( )
{
//if (state)
// delete state;
2013-06-26 14:18:27 +03:00
//state=nullptr;
2008-12-22 19:48:41 +02:00
}
const std : : string & CGObjectInstance : : getHoverText ( ) const
{
return hoverName ;
}
2013-03-03 20:06:03 +03:00
void CGObjectInstance : : setOwner ( PlayerColor ow )
2007-11-19 00:58:28 +02:00
{
//if (state)
// state->owner = ow;
//else
tempOwner = ow ;
2007-10-27 22:38:48 +03:00
}
int CGObjectInstance : : getWidth ( ) const //returns width of object graphic in tiles
{
2008-06-17 20:48:32 +03:00
return defInfo - > width ;
2007-10-27 22:38:48 +03:00
}
int CGObjectInstance : : getHeight ( ) const //returns height of object graphic in tiles
{
2009-03-12 01:25:59 +02:00
return defInfo - > height ;
2007-10-27 22:38:48 +03:00
}
2008-09-26 17:16:01 +03:00
bool CGObjectInstance : : visitableAt ( int x , int y ) const //returns true if object is visitable at location (x, y) form left top tile of image (x, y in tiles)
2007-10-27 22:38:48 +03:00
{
2013-06-26 14:18:27 +03:00
if ( defInfo = = nullptr )
2009-03-12 01:25:59 +02:00
{
2013-06-26 14:18:27 +03:00
logGlobal - > warnStream ( ) < < " Warning: VisitableAt for obj " < < id . getNum ( ) < < " : nullptr defInfo! " ;
2007-10-27 22:38:48 +03:00
return false ;
2009-03-12 01:25:59 +02:00
}
if ( ( defInfo - > visitMap [ y ] > > ( 7 - x ) ) & 1 )
{
2007-08-09 19:28:01 +03:00
return true ;
2009-03-12 01:25:59 +02:00
}
2007-10-27 22:38:48 +03:00
return false ;
}
2008-09-26 17:16:01 +03:00
bool CGObjectInstance : : blockingAt ( int x , int y ) const
{
2013-06-26 14:18:27 +03:00
if ( x < 0 | | y < 0 | | x > = getWidth ( ) | | y > = getHeight ( ) | | defInfo = = nullptr )
2008-09-26 17:16:01 +03:00
return false ;
if ( ( defInfo - > blockMap [ y + 6 - getHeight ( ) ] > > ( 7 - ( 8 - getWidth ( ) + x ) ) ) & 1 )
2009-07-30 15:49:45 +03:00
return false ;
return true ;
2008-09-26 17:16:01 +03:00
}
2009-07-01 18:58:20 +03:00
bool CGObjectInstance : : coveringAt ( int x , int y ) const
{
2012-05-19 14:47:26 +03:00
//input coordinates are always negative
x = - x ;
y = - y ;
2012-02-21 17:08:42 +03:00
# if USE_COVERAGE_MAP
2012-05-19 14:47:26 +03:00
//NOTE: this code may be broken
2012-07-19 21:52:44 +03:00
if ( ( defInfo - > coverageMap [ y ] > > ( 7 - ( x ) ) ) & 1
2009-12-22 23:53:50 +02:00
| | ( defInfo - > shadowCoverage [ y ] > > ( 7 - ( x ) ) ) & 1 )
2009-07-01 18:58:20 +03:00
return true ;
return false ;
2012-02-21 17:18:58 +03:00
# else
2012-05-19 14:47:26 +03:00
return x > = 0 & & y > = 0 & & x < getWidth ( ) & & y < getHeight ( ) ;
# endif
}
bool CGObjectInstance : : hasShadowAt ( int x , int y ) const
{
# if USE_COVERAGE_MAP
//NOTE: this code may be broken
if ( ( defInfo - > shadowCoverage [ y ] > > ( 7 - ( x ) ) ) & 1 )
return true ;
return false ;
# else
return coveringAt ( x , y ) ; // ignore unreliable shadowCoverage map
2012-02-21 17:08:42 +03:00
# endif
2009-07-01 18:58:20 +03:00
}
2009-07-30 15:49:45 +03:00
std : : set < int3 > CGObjectInstance : : getBlockedPos ( ) const
{
std : : set < int3 > ret ;
for ( int w = 0 ; w < getWidth ( ) ; + + w )
{
for ( int h = 0 ; h < getHeight ( ) ; + + h )
{
if ( blockingAt ( w , h ) )
ret . insert ( int3 ( pos . x - getWidth ( ) + w + 1 , pos . y - getHeight ( ) + h + 1 , pos . z ) ) ;
}
}
return ret ;
}
2007-10-27 22:38:48 +03:00
bool CGObjectInstance : : operator < ( const CGObjectInstance & cmp ) const //screen printing priority comparing
{
2007-11-24 00:33:55 +02:00
if ( defInfo - > printPriority = = 1 & & cmp . defInfo - > printPriority = = 0 )
2007-10-27 22:38:48 +03:00
return true ;
2007-11-24 00:33:55 +02:00
if ( cmp . defInfo - > printPriority = = 1 & & defInfo - > printPriority = = 0 )
2007-08-09 19:28:01 +03:00
return false ;
if ( this - > pos . y < cmp . pos . y )
return true ;
if ( this - > pos . y > cmp . pos . y )
return false ;
2012-09-23 21:01:04 +03:00
if ( cmp . ID = = Obj : : HERO & & ID ! = Obj : : HERO )
2008-02-23 21:20:41 +02:00
return true ;
2012-09-23 21:01:04 +03:00
if ( cmp . ID ! = Obj : : HERO & & ID = = Obj : : HERO )
2008-02-23 21:20:41 +02:00
return false ;
2007-10-28 13:34:33 +02:00
if ( ! defInfo - > isVisitable ( ) & & cmp . defInfo - > isVisitable ( ) )
2007-08-09 19:28:01 +03:00
return true ;
2007-10-28 13:34:33 +02:00
if ( ! cmp . defInfo - > isVisitable ( ) & & defInfo - > isVisitable ( ) )
2007-08-09 19:28:01 +03:00
return false ;
if ( this - > pos . x < cmp . pos . x )
return true ;
return false ;
}
2007-10-26 20:55:33 +03:00
2008-12-22 19:48:41 +02:00
void CGObjectInstance : : initObj ( )
{
2010-07-09 02:03:27 +03:00
switch ( ID )
{
2012-09-23 21:01:04 +03:00
case Obj : : TAVERN :
2010-07-09 02:03:27 +03:00
blockVisit = true ;
break ;
}
2008-12-22 19:48:41 +02:00
}
2008-08-02 18:08:03 +03:00
2009-02-20 14:39:27 +02:00
void CGObjectInstance : : setProperty ( ui8 what , ui32 val )
{
switch ( what )
{
2010-05-02 21:20:26 +03:00
case ObjProperty : : OWNER :
2013-03-03 20:06:03 +03:00
tempOwner = PlayerColor ( val ) ;
2009-02-20 14:39:27 +02:00
break ;
2010-05-02 21:20:26 +03:00
case ObjProperty : : BLOCKVIS :
2009-02-20 14:39:27 +02:00
blockVisit = val ;
break ;
2010-05-02 21:20:26 +03:00
case ObjProperty : : ID :
2013-02-11 02:24:57 +03:00
ID = Obj ( val ) ;
2009-02-20 14:39:27 +02:00
break ;
2010-07-31 03:26:34 +03:00
case ObjProperty : : SUBID :
subID = val ;
break ;
2009-02-20 14:39:27 +02:00
}
setPropertyDer ( what , val ) ;
}
void CGObjectInstance : : setPropertyDer ( ui8 what , ui32 val )
{ }
2009-03-12 01:25:59 +02:00
int3 CGObjectInstance : : getSightCenter ( ) const
{
//return vistiable tile if possible
for ( int i = 0 ; i < 8 ; i + + )
for ( int j = 0 ; j < 6 ; j + + )
if ( visitableAt ( i , j ) )
return ( pos + int3 ( i - 7 , j - 5 , 0 ) ) ;
return pos ;
}
int CGObjectInstance : : getSightRadious ( ) const
{
return 3 ;
}
2013-06-29 16:05:48 +03:00
void CGObjectInstance : : getSightTiles ( std : : unordered_set < int3 , ShashInt3 > & tiles ) const //returns reference to the set
2009-11-11 19:45:03 +02:00
{
2009-12-01 12:23:23 +02:00
cb - > getTilesInRange ( tiles , getSightCenter ( ) , getSightRadious ( ) , tempOwner , 1 ) ;
2009-11-11 19:45:03 +02:00
}
2013-03-03 20:06:03 +03:00
void CGObjectInstance : : hideTiles ( PlayerColor ourplayer , int radius ) const
2010-06-19 12:13:10 +03:00
{
2012-09-24 19:14:53 +03:00
for ( auto i = cb - > gameState ( ) - > teams . begin ( ) ; i ! = cb - > gameState ( ) - > teams . end ( ) ; i + + )
2010-06-19 12:13:10 +03:00
{
2010-08-06 16:14:10 +03:00
if ( ! vstd : : contains ( i - > second . players , ourplayer ) ) //another team
2010-06-19 12:13:10 +03:00
{
2013-06-29 16:05:48 +03:00
for ( auto & elem : i - > second . players )
if ( cb - > getPlayer ( elem ) - > status = = EPlayerStatus : : INGAME ) //seek for living player (if any)
2010-08-06 16:14:10 +03:00
{
FoWChange fw ;
fw . mode = 0 ;
2013-06-29 16:05:48 +03:00
fw . player = elem ;
cb - > getTilesInRange ( fw . tiles , pos , radius , ( elem ) , - 1 ) ;
2010-08-06 16:14:10 +03:00
cb - > sendAndApply ( & fw ) ;
break ;
}
2010-06-19 12:13:10 +03:00
}
}
}
2009-07-14 19:20:15 +03:00
int3 CGObjectInstance : : getVisitableOffset ( ) const
{
for ( int y = 0 ; y < 6 ; y + + )
for ( int x = 0 ; x < 8 ; x + + )
if ( ( defInfo - > visitMap [ 5 - y ] > > x ) & 1 )
return int3 ( x , y , 0 ) ;
2013-04-09 17:31:36 +03:00
logGlobal - > warnStream ( ) < < " Warning: getVisitableOffset called on non-visitable obj! " ;
2009-07-14 19:20:15 +03:00
return int3 ( - 1 , - 1 , - 1 ) ;
}
2009-07-19 10:16:33 +03:00
void CGObjectInstance : : getNameVis ( std : : string & hname ) const
{
const CGHeroInstance * h = cb - > getSelectedHero ( cb - > getCurrentPlayer ( ) ) ;
hname = VLC - > generaltexth - > names [ ID ] ;
2012-07-19 21:52:44 +03:00
if ( h )
2009-07-19 10:16:33 +03:00
{
2013-01-13 15:40:24 +03:00
const bool visited = h - > hasBonusFrom ( Bonus : : OBJECT , ID ) ;
hname + " " + visitedTxt ( visited ) ;
2009-07-19 10:16:33 +03:00
}
}
2013-02-14 02:55:42 +03:00
void CGObjectInstance : : giveDummyBonus ( ObjectInstanceID heroID , ui8 duration ) const
2009-07-19 10:16:33 +03:00
{
GiveBonus gbonus ;
2010-05-02 21:20:26 +03:00
gbonus . bonus . type = Bonus : : NONE ;
2013-02-14 02:55:42 +03:00
gbonus . id = heroID . getNum ( ) ;
2009-07-19 10:16:33 +03:00
gbonus . bonus . duration = duration ;
2010-05-02 21:20:26 +03:00
gbonus . bonus . source = Bonus : : OBJECT ;
2011-02-20 20:32:39 +02:00
gbonus . bonus . sid = ID ;
2009-07-19 10:16:33 +03:00
cb - > giveHeroBonus ( & gbonus ) ;
}
2009-07-26 06:33:13 +03:00
void CGObjectInstance : : onHeroVisit ( const CGHeroInstance * h ) const
{
2010-07-09 02:03:27 +03:00
switch ( ID )
{
2012-09-23 21:01:04 +03:00
case Obj : : HILL_FORT :
2010-07-22 03:32:45 +03:00
{
2013-02-14 02:55:42 +03:00
openWindow ( OpenWindow : : HILL_FORT_WINDOW , id . getNum ( ) , h - > id . getNum ( ) ) ;
2010-07-22 03:32:45 +03:00
}
break ;
2012-09-23 21:01:04 +03:00
case Obj : : SANCTUARY :
2010-07-09 03:54:17 +03:00
{
2013-01-12 13:32:03 +03:00
//You enter the sanctuary and immediately feel as if a great weight has been lifted off your shoulders. You feel safe here.
showInfoDialog ( h , 114 , soundBase : : GETPROTECTION ) ;
2010-07-09 03:54:17 +03:00
}
break ;
2012-09-23 21:01:04 +03:00
case Obj : : TAVERN :
2010-07-09 03:54:17 +03:00
{
2013-02-14 02:55:42 +03:00
openWindow ( OpenWindow : : TAVERN_WINDOW , h - > id . getNum ( ) , id . getNum ( ) ) ;
2010-07-09 03:54:17 +03:00
}
break ;
2010-07-09 02:03:27 +03:00
}
2009-07-26 06:33:13 +03:00
}
2009-12-20 19:14:14 +02:00
ui8 CGObjectInstance : : getPassableness ( ) const
{
return 0 ;
}
2010-05-15 11:33:32 +03:00
int3 CGObjectInstance : : visitablePos ( ) const
{
return pos - getVisitableOffset ( ) ;
}
2011-02-24 17:05:21 +02:00
bool CGObjectInstance : : isVisitable ( ) const
{
for ( int g = 0 ; g < ARRAY_COUNT ( defInfo - > visitMap ) ; + + g )
{
if ( defInfo - > visitMap [ g ] ! = 0 )
{
return true ;
}
}
return false ;
}
2013-04-20 14:34:01 +03:00
bool CGObjectInstance : : passableFor ( PlayerColor color ) const
{
return getPassableness ( ) & 1 < < color . getNum ( ) ;
}
2009-05-24 01:57:39 +03:00
static int lowestSpeed ( const CGHeroInstance * chi )
2007-10-27 22:38:48 +03:00
{
2010-05-02 21:20:26 +03:00
if ( ! chi - > Slots ( ) . size ( ) )
2008-12-22 19:48:41 +02:00
{
2013-04-09 17:31:36 +03:00
logGlobal - > errorStream ( ) < < " Error! Hero " < < chi - > id . getNum ( ) < < " ( " < < chi - > name < < " ) has no army! " ;
2008-12-22 19:48:41 +02:00
return 20 ;
}
2013-06-29 16:05:48 +03:00
auto i = chi - > Slots ( ) . begin ( ) ;
2010-05-02 21:20:26 +03:00
//TODO? should speed modifiers (eg from artifacts) affect hero movement?
2010-11-22 02:34:46 +02:00
int ret = ( i + + ) - > second - > valOfBonuses ( Bonus : : STACKS_SPEED ) ;
2010-05-02 21:20:26 +03:00
for ( ; i ! = chi - > Slots ( ) . end ( ) ; i + + )
2008-12-22 19:48:41 +02:00
{
2010-11-22 02:34:46 +02:00
ret = std : : min ( ret , i - > second - > valOfBonuses ( Bonus : : STACKS_SPEED ) ) ;
2008-12-22 19:48:41 +02:00
}
return ret ;
2007-10-27 22:38:48 +03:00
}
2008-12-22 19:48:41 +02:00
2011-12-14 00:23:17 +03:00
ui32 CGHeroInstance : : getTileCost ( const TerrainTile & dest , const TerrainTile & from ) const
2007-10-27 22:38:48 +03:00
{
2009-02-12 16:44:58 +02:00
//base move cost
unsigned ret = 100 ;
2012-07-19 21:52:44 +03:00
2009-02-12 16:44:58 +02:00
//if there is road both on dest and src tiles - use road movement cost
2012-11-06 19:39:29 +03:00
if ( dest . roadType ! = ERoadType : : NO_ROAD & & from . roadType ! = ERoadType : : NO_ROAD )
2008-09-28 16:29:37 +03:00
{
2012-10-26 20:51:05 +03:00
int road = std : : min ( dest . roadType , from . roadType ) ; //used road ID
2009-02-12 16:44:58 +02:00
switch ( road )
2008-09-28 16:29:37 +03:00
{
2012-10-26 20:51:05 +03:00
case ERoadType : : DIRT_ROAD :
2009-02-12 16:44:58 +02:00
ret = 75 ;
2008-09-28 16:29:37 +03:00
break ;
2012-10-26 20:51:05 +03:00
case ERoadType : : GRAVEL_ROAD :
2009-02-12 16:44:58 +02:00
ret = 65 ;
2008-09-28 16:29:37 +03:00
break ;
2012-10-26 20:51:05 +03:00
case ERoadType : : COBBLESTONE_ROAD :
2009-02-12 16:44:58 +02:00
ret = 50 ;
2008-09-28 16:29:37 +03:00
break ;
2009-02-12 16:44:58 +02:00
default :
2013-04-09 17:31:36 +03:00
logGlobal - > errorStream ( ) < < " Unknown road type: " < < road < < " ... Something wrong! " ;
2008-09-28 16:29:37 +03:00
break ;
}
}
2012-07-19 21:52:44 +03:00
else
2007-10-27 22:38:48 +03:00
{
2012-09-06 13:39:48 +03:00
//FIXME: in H3 presence of Nomad in army will remove terrain penalty for sand. Bonus not implemented in VCMI
2012-09-05 15:49:23 +03:00
2012-09-06 13:39:48 +03:00
// NOTE: in H3 neutral stacks will ignore terrain penalty only if placed as topmost stack(s) in hero army.
// This is clearly bug in H3 however intended behaviour is not clear.
// Current VCMI behaviour will ignore neutrals in calculations so army in VCMI
// will always have best penalty without any influence from player-defined stacks order
bool nativeArmy = true ;
2013-06-29 16:05:48 +03:00
for ( auto stack : stacks )
2012-09-06 13:39:48 +03:00
{
2013-04-21 15:49:26 +03:00
int nativeTerrain = VLC - > townh - > factions [ stack . second - > type - > faction ] - > nativeTerrain ;
2012-09-06 13:39:48 +03:00
2012-11-06 19:39:29 +03:00
if ( nativeTerrain ! = - 1 & & nativeTerrain ! = from . terType )
2012-09-06 13:39:48 +03:00
{
nativeArmy = false ;
break ;
}
}
if ( ! nativeArmy )
2012-11-06 19:39:29 +03:00
ret = VLC - > heroh - > terrCosts [ from . terType ] ;
2012-09-06 13:39:48 +03:00
}
2007-10-27 22:38:48 +03:00
return ret ;
}
2012-09-06 13:39:48 +03:00
2007-10-27 22:38:48 +03:00
int3 CGHeroInstance : : convertPosition ( int3 src , bool toh3m ) //toh3m=true: manifest->h3m; toh3m=false: h3m->manifest
{
if ( toh3m )
{
src . x + = 1 ;
return src ;
}
else
{
src . x - = 1 ;
return src ;
}
}
int3 CGHeroInstance : : getPosition ( bool h3m ) const //h3m=true - returns position of hero object; h3m=false - returns position of hero 'manifestation'
{
2008-12-23 15:59:03 +02:00
if ( h3m )
{
2007-10-27 22:38:48 +03:00
return pos ;
2008-12-23 15:59:03 +02:00
}
else
{
return convertPosition ( pos , false ) ;
}
2007-10-27 22:38:48 +03:00
}
2008-10-18 14:41:24 +03:00
2007-10-27 22:38:48 +03:00
bool CGHeroInstance : : canWalkOnSea ( ) const
2007-10-26 20:55:33 +03:00
{
2010-05-15 18:00:19 +03:00
return hasBonusOfType ( Bonus : : FLYING_MOVEMENT ) | | hasBonusOfType ( Bonus : : WATER_WALKING ) ;
2007-10-26 20:55:33 +03:00
}
2010-05-15 18:00:19 +03:00
2013-02-12 22:49:40 +03:00
ui8 CGHeroInstance : : getSecSkillLevel ( SecondarySkill skill ) const
2008-02-25 01:06:27 +02:00
{
2013-06-29 16:05:48 +03:00
for ( auto & elem : secSkills )
if ( elem . first = = skill )
return elem . second ;
2008-09-28 16:29:37 +03:00
return 0 ;
2008-02-25 01:06:27 +02:00
}
2010-07-31 16:55:05 +03:00
2013-02-12 22:49:40 +03:00
void CGHeroInstance : : setSecSkillLevel ( SecondarySkill which , int val , bool abs )
2010-07-31 16:55:05 +03:00
{
if ( getSecSkillLevel ( which ) = = 0 )
{
2013-02-12 22:49:40 +03:00
secSkills . push_back ( std : : pair < SecondarySkill , ui8 > ( which , val ) ) ;
2010-07-31 16:55:05 +03:00
updateSkill ( which , val ) ;
}
else
{
2013-06-29 16:05:48 +03:00
for ( auto & elem : secSkills )
2010-07-31 16:55:05 +03:00
{
2013-06-29 16:05:48 +03:00
if ( elem . first = = which )
2010-07-31 16:55:05 +03:00
{
if ( abs )
2013-06-29 16:05:48 +03:00
elem . second = val ;
2010-07-31 16:55:05 +03:00
else
2013-06-29 16:05:48 +03:00
elem . second + = val ;
2010-07-31 16:55:05 +03:00
2013-06-29 16:05:48 +03:00
if ( elem . second > 3 ) //workaround to avoid crashes when same sec skill is given more than once
2010-07-31 16:55:05 +03:00
{
2013-04-09 17:31:36 +03:00
logGlobal - > warnStream ( ) < < " Warning: Skill " < < which < < " increased over limit! Decreasing to Expert. " ;
2013-06-29 16:05:48 +03:00
elem . second = 3 ;
2010-07-31 16:55:05 +03:00
}
2013-06-29 16:05:48 +03:00
updateSkill ( which , elem . second ) ; //when we know final value
2010-07-31 16:55:05 +03:00
}
}
}
}
2012-12-18 14:24:13 +03:00
bool CGHeroInstance : : canLearnSkill ( ) const
{
return secSkills . size ( ) < GameConstants : : SKILL_PER_HERO ;
}
2008-10-26 22:58:34 +02:00
int CGHeroInstance : : maxMovePoints ( bool onLand ) const
{
2012-09-06 13:39:48 +03:00
int base ;
2010-02-10 04:56:00 +02:00
if ( onLand )
{
2012-09-06 13:39:48 +03:00
// used function is f(x) = 66.6x + 1300, rounded to second digit, where x is lowest speed in army
static const int baseSpeed = 1300 ; // base speed from creature with 0 speed
int armySpeed = lowestSpeed ( this ) * 20 / 3 ;
base = armySpeed * 10 + baseSpeed ; // separate *10 is intentional to receive same rounding as in h3
vstd : : abetween ( base , 1500 , 2000 ) ; // base speed is limited by these values
2010-02-10 04:56:00 +02:00
}
else
{
base = 1500 ; //on water base movement is always 1500 (speed of army doesn't matter)
}
2012-07-19 21:52:44 +03:00
2013-01-12 16:53:02 +03:00
const Bonus : : BonusType bt = onLand ? Bonus : : LAND_MOVEMENT : Bonus : : SEA_MOVEMENT ;
const int bonus = valOfBonuses ( Bonus : : MOVEMENT ) + valOfBonuses ( bt ) ;
2008-10-26 22:58:34 +02:00
2013-02-04 22:43:16 +03:00
const int subtype = onLand ? SecondarySkill : : LOGISTICS : SecondarySkill : : NAVIGATION ;
2013-01-12 16:53:02 +03:00
const double modifier = valOfBonuses ( Bonus : : SECONDARY_SKILL_PREMY , subtype ) / 100.0 ;
return int ( base * ( 1 + modifier ) ) + bonus ;
2008-10-26 22:58:34 +02:00
}
2009-04-04 01:34:31 +03:00
2008-12-22 19:48:41 +02:00
CGHeroInstance : : CGHeroInstance ( )
2010-03-11 01:16:30 +02:00
: IBoatGenerator ( this )
2008-12-22 19:48:41 +02:00
{
2011-07-13 21:39:02 +03:00
setNodeType ( HERO ) ;
2012-09-23 21:01:04 +03:00
ID = Obj : : HERO ;
2008-12-22 19:48:41 +02:00
tacticFormationEnabled = inTownGarrison = false ;
mana = movement = portrait = level = - 1 ;
isStanding = true ;
moveDir = 4 ;
exp = 0xffffffff ;
2013-06-26 14:18:27 +03:00
visitedTown = nullptr ;
type = nullptr ;
boat = nullptr ;
commander = nullptr ;
2011-09-13 06:31:17 +03:00
sex = 0xff ;
2013-02-04 22:43:16 +03:00
secSkills . push_back ( std : : make_pair ( SecondarySkill : : DEFAULT , - 1 ) ) ;
2008-12-22 19:48:41 +02:00
}
2013-05-19 01:30:48 +03:00
void CGHeroInstance : : initHero ( HeroTypeID SUBID )
2008-12-22 19:48:41 +02:00
{
2013-05-19 01:30:48 +03:00
subID = SUBID . getNum ( ) ;
2008-12-22 19:48:41 +02:00
initHero ( ) ;
}
void CGHeroInstance : : initHero ( )
{
2010-05-02 21:20:26 +03:00
assert ( validTypes ( true ) ) ;
2012-09-23 21:01:04 +03:00
if ( ID = = Obj : : HERO )
2009-02-14 21:12:40 +02:00
initHeroDefInfo ( ) ;
2008-12-22 19:48:41 +02:00
if ( ! type )
type = VLC - > heroh - > heroes [ subID ] ;
2012-12-16 16:47:53 +03:00
2013-02-11 02:24:57 +03:00
if ( ! vstd : : contains ( spells , SpellID : : PRESET ) ) //hero starts with a spell
2012-12-16 16:47:53 +03:00
{
2013-06-29 16:05:48 +03:00
for ( auto spellID : type - > spells )
2012-12-16 16:47:53 +03:00
spells . insert ( spellID ) ;
}
2009-09-14 01:45:58 +03:00
else //remove placeholder
2013-02-11 02:24:57 +03:00
spells - = SpellID : : PRESET ;
2009-09-14 01:45:58 +03:00
2013-03-02 19:55:51 +03:00
if ( ! getArt ( ArtifactPosition : : MACH4 ) & & ! getArt ( ArtifactPosition : : SPELLBOOK ) & & type - > haveSpellBook ) //no catapult means we haven't read pre-existent set -> use default rules for spellbook
2011-12-14 00:23:17 +03:00
putArtifact ( ArtifactPosition : : SPELLBOOK , CArtifactInstance : : createNewArtifactInstance ( 0 ) ) ;
2008-12-22 19:48:41 +02:00
2011-12-14 00:23:17 +03:00
if ( ! getArt ( ArtifactPosition : : MACH4 ) )
putArtifact ( ArtifactPosition : : MACH4 , CArtifactInstance : : createNewArtifactInstance ( 3 ) ) ; //everyone has a catapult
2012-07-19 21:52:44 +03:00
2008-12-22 19:48:41 +02:00
if ( portrait < 0 | | portrait = = 255 )
2012-12-16 16:47:53 +03:00
portrait = type - > imageIndex ;
2010-05-02 21:20:26 +03:00
if ( ! hasBonus ( Selector : : sourceType ( Bonus : : HERO_BASE_SKILL ) ) )
2008-12-22 19:48:41 +02:00
{
2012-09-23 21:01:04 +03:00
for ( int g = 0 ; g < GameConstants : : PRIMARY_SKILLS ; + + g )
{
2012-12-14 18:32:53 +03:00
pushPrimSkill ( static_cast < PrimarySkill : : PrimarySkill > ( g ) , type - > heroClass - > primarySkillInitial [ g ] ) ;
2012-09-23 21:01:04 +03:00
}
2008-12-22 19:48:41 +02:00
}
2013-02-12 22:49:40 +03:00
if ( secSkills . size ( ) = = 1 & & secSkills [ 0 ] = = std : : pair < SecondarySkill , ui8 > ( SecondarySkill : : DEFAULT , - 1 ) ) //set secondary skills to default
2008-12-22 19:48:41 +02:00
secSkills = type - > secSkillsInit ;
if ( ! name . length ( ) )
name = type - > name ;
2010-08-25 17:57:58 +03:00
if ( sex = = 0xFF ) //sex is default
sex = type - > sex ;
2010-05-02 21:20:26 +03:00
setFormation ( false ) ;
if ( ! stacksCount ( ) ) //standard army//initial army
2008-12-22 19:48:41 +02:00
{
2010-07-08 08:52:11 +03:00
initArmy ( ) ;
2008-12-22 19:48:41 +02:00
}
2010-05-02 21:20:26 +03:00
assert ( validTypes ( ) ) ;
2010-07-08 08:52:11 +03:00
2013-02-04 15:32:53 +03:00
if ( exp = = 0xffffffff )
{
initExp ( ) ;
}
else if ( ID ! = Obj : : PRISON )
{
level = VLC - > heroh - > level ( exp ) ;
}
else //warp hero at the beginning of next turn
{
level = 1 ;
2012-04-22 20:38:36 +03:00
}
2013-02-09 21:18:55 +03:00
if ( VLC - > modh - > modules . COMMANDERS & & ! commander )
2013-02-04 22:22:19 +03:00
{
2013-04-21 15:49:26 +03:00
commander = new CCommanderInstance ( VLC - > townh - > factions [ type - > heroClass - > faction ] - > commander ) ;
2013-02-04 22:22:19 +03:00
commander - > setArmyObj ( castToArmyObj ( ) ) ; //TODO: separate function for setting commanders
commander - > giveStackExp ( exp ) ; //after our exp is set
}
2008-12-22 19:48:41 +02:00
hoverName = VLC - > generaltexth - > allTexts [ 15 ] ;
boost : : algorithm : : replace_first ( hoverName , " %s " , name ) ;
boost : : algorithm : : replace_first ( hoverName , " %s " , type - > heroClass - > name ) ;
2009-04-04 01:34:31 +03:00
2010-08-15 10:39:07 +03:00
if ( mana < 0 )
mana = manaLimit ( ) ;
2008-12-22 19:48:41 +02:00
}
2013-06-26 14:18:27 +03:00
void CGHeroInstance : : initArmy ( IArmyDescriptor * dst /*= nullptr*/ )
2010-07-08 08:52:11 +03:00
{
if ( ! dst )
dst = this ;
int howManyStacks = 0 ; //how many stacks will hero receives <1 - 3>
int pom = ran ( ) % 100 ;
int warMachinesGiven = 0 ;
if ( pom < 9 )
howManyStacks = 1 ;
else if ( pom < 79 )
howManyStacks = 2 ;
else
howManyStacks = 3 ;
2012-12-16 16:47:53 +03:00
vstd : : amin ( howManyStacks , type - > initialArmy . size ( ) ) ;
2010-07-26 23:56:39 +03:00
for ( int stackNo = 0 ; stackNo < howManyStacks ; stackNo + + )
2010-07-08 08:52:11 +03:00
{
2012-12-03 19:00:17 +03:00
auto & stack = type - > initialArmy [ stackNo ] ;
2012-04-10 05:30:43 +03:00
2012-12-03 19:00:17 +03:00
int range = stack . maxAmount - stack . minAmount ;
int count = ran ( ) % ( range + 1 ) + stack . minAmount ;
2010-07-08 08:52:11 +03:00
2013-02-07 20:34:50 +03:00
if ( stack . creature > = CreatureID : : CATAPULT & &
stack . creature < = CreatureID : : ARROW_TOWERS ) //war machine
2010-07-08 08:52:11 +03:00
{
warMachinesGiven + + ;
2010-12-30 16:41:46 +02:00
if ( dst ! = this )
continue ;
2013-02-07 20:34:50 +03:00
int slot = - 1 ;
2013-02-11 02:24:57 +03:00
ArtifactID aid = ArtifactID : : NONE ;
2012-12-03 19:00:17 +03:00
switch ( stack . creature )
2010-07-08 08:52:11 +03:00
{
2013-02-07 20:34:50 +03:00
case CreatureID : : CATAPULT :
2011-12-14 00:23:17 +03:00
slot = ArtifactPosition : : MACH4 ;
2013-02-07 20:34:50 +03:00
aid = ArtifactID : : CATAPULT ;
2010-07-08 08:52:11 +03:00
break ;
default :
2013-02-07 20:34:50 +03:00
aid = CArtHandler : : creatureToMachineID ( stack . creature ) ;
2010-12-30 16:41:46 +02:00
slot = 9 + aid ;
2010-07-08 08:52:11 +03:00
break ;
}
2013-02-12 22:49:40 +03:00
auto convSlot = ArtifactPosition ( slot ) ;
2013-02-07 02:24:43 +03:00
if ( ! getArt ( convSlot ) )
putArtifact ( convSlot , CArtifactInstance : : createNewArtifactInstance ( aid ) ) ;
2010-12-30 16:41:46 +02:00
else
2013-04-09 17:31:36 +03:00
logGlobal - > warnStream ( ) < < " Hero " < < name < < " already has artifact at " < < slot < < " , omitting giving " < < aid ;
2010-07-08 08:52:11 +03:00
}
else
2013-02-16 17:03:47 +03:00
dst - > setCreature ( SlotID ( stackNo - warMachinesGiven ) , stack . creature , count ) ;
2010-07-08 08:52:11 +03:00
}
}
2009-02-01 16:11:41 +02:00
void CGHeroInstance : : initHeroDefInfo ( )
{
2012-09-23 21:01:04 +03:00
if ( ! defInfo | | defInfo - > id ! = Obj : : HERO )
2009-02-01 16:11:41 +02:00
{
defInfo = new CGDefInfo ( ) ;
2012-09-23 21:01:04 +03:00
defInfo - > id = Obj : : HERO ;
2009-02-01 16:11:41 +02:00
defInfo - > subid = subID ;
defInfo - > printPriority = 0 ;
defInfo - > visitDir = 0xff ;
}
for ( int i = 0 ; i < 6 ; i + + )
{
2009-07-13 00:17:35 +03:00
defInfo - > blockMap [ i ] = 255 ;
defInfo - > visitMap [ i ] = 0 ;
defInfo - > coverageMap [ i ] = 0 ;
2009-12-22 23:53:50 +02:00
defInfo - > shadowCoverage [ i ] = 0 ;
2009-02-01 16:11:41 +02:00
}
defInfo - > blockMap [ 5 ] = 253 ;
defInfo - > visitMap [ 5 ] = 2 ;
2009-07-13 00:17:35 +03:00
defInfo - > coverageMap [ 4 ] = defInfo - > coverageMap [ 5 ] = 224 ;
2009-02-01 16:11:41 +02:00
}
2008-12-22 19:48:41 +02:00
CGHeroInstance : : ~ CGHeroInstance ( )
{
2013-04-21 19:38:31 +03:00
commander . dellNull ( ) ;
2008-12-22 19:48:41 +02:00
}
bool CGHeroInstance : : needsLastStack ( ) const
{
return true ;
}
2013-04-21 19:38:31 +03:00
2008-12-27 03:01:59 +02:00
void CGHeroInstance : : onHeroVisit ( const CGHeroInstance * h ) const
2008-12-22 19:48:41 +02:00
{
2009-06-28 11:21:50 +03:00
if ( h = = this ) return ; //exclude potential self-visiting
2012-09-23 21:01:04 +03:00
if ( ID = = Obj : : HERO )
2008-12-22 19:48:41 +02:00
{
2010-08-13 13:46:08 +03:00
if ( cb - > gameState ( ) - > getPlayerRelations ( tempOwner , h - > tempOwner ) ) //our or ally hero
2009-02-14 21:12:40 +02:00
{
//exchange
2010-08-12 18:54:25 +03:00
cb - > heroExchange ( h - > id , id ) ;
2009-02-14 21:12:40 +02:00
}
2009-09-13 01:17:23 +03:00
else //battle
2009-02-14 21:12:40 +02:00
{
2009-09-13 01:17:23 +03:00
if ( visitedTown ) //we're in town
visitedTown - > onHeroVisit ( h ) ; //town will handle attacking
else
cb - > startBattleI ( h , this ) ;
2009-02-14 21:12:40 +02:00
}
2008-12-22 19:48:41 +02:00
}
2012-09-23 21:01:04 +03:00
else if ( ID = = Obj : : PRISON )
2008-12-22 19:48:41 +02:00
{
2013-01-12 13:32:03 +03:00
int txt_id ;
2009-04-24 00:09:10 +03:00
2013-02-04 15:32:53 +03:00
if ( cb - > getHeroCount ( h - > tempOwner , false ) < GameConstants : : MAX_HEROES_PER_PLAYER ) //free hero slot
2009-02-14 21:12:40 +02:00
{
2009-02-20 12:36:15 +02:00
cb - > changeObjPos ( id , pos + int3 ( 1 , 0 , 0 ) , 0 ) ;
2013-02-04 15:32:53 +03:00
//update hero parameters
SetMovePoints smp ;
smp . hid = id ;
smp . val = maxMovePoints ( true ) ; //TODO: hota prison on water?
cb - > setMovePoints ( & smp ) ;
cb - > setManaPoints ( id , manaLimit ( ) ) ;
2012-09-23 21:01:04 +03:00
cb - > setObjProperty ( id , ObjProperty : : ID , Obj : : HERO ) ; //set ID to 34
2009-02-14 21:12:40 +02:00
cb - > giveHero ( id , h - > tempOwner ) ; //recreates def and adds hero to player
2013-01-12 13:32:03 +03:00
txt_id = 102 ;
2009-02-14 21:12:40 +02:00
}
else //already 8 wandering heroes
{
2013-01-12 13:32:03 +03:00
txt_id = 103 ;
2009-02-14 21:12:40 +02:00
}
2009-04-24 00:09:10 +03:00
2013-01-12 13:32:03 +03:00
showInfoDialog ( h , txt_id , soundBase : : ROGUE ) ;
2008-12-22 19:48:41 +02:00
}
}
const std : : string & CGHeroInstance : : getBiography ( ) const
{
if ( biography . length ( ) )
return biography ;
2012-12-16 16:47:53 +03:00
return type - > biography ;
2008-12-22 19:48:41 +02:00
}
2012-12-25 20:23:26 +03:00
void CGHeroInstance : : initObj ( ) //TODO: use bonus system
2008-12-22 19:48:41 +02:00
{
2008-12-27 03:01:59 +02:00
blockVisit = true ;
2013-06-29 16:05:48 +03:00
auto hs = new HeroSpecial ( ) ;
2013-01-20 19:31:18 +03:00
hs - > setNodeType ( CBonusSystemNode : : specialty ) ;
attachTo ( hs ) ; //do we ever need to detach it?
2010-07-07 05:29:07 +03:00
if ( ! type )
2013-02-04 15:32:53 +03:00
initHero ( ) ; //TODO: set up everything for prison before specialties are configured
2010-07-07 05:29:07 +03:00
2013-06-29 16:05:48 +03:00
for ( const auto & spec : type - > spec ) //TODO: unfity with bonus system
2010-07-06 10:32:40 +03:00
{
2013-06-29 16:05:48 +03:00
auto bonus = new Bonus ( ) ;
2013-01-12 16:53:02 +03:00
bonus - > val = spec . val ;
2013-02-14 02:55:42 +03:00
bonus - > sid = id . getNum ( ) ; //from the hero, specialty has no unique id
2010-11-20 02:03:31 +02:00
bonus - > duration = Bonus : : PERMANENT ;
bonus - > source = Bonus : : HERO_SPECIAL ;
2013-01-12 16:53:02 +03:00
switch ( spec . type )
2010-07-06 10:32:40 +03:00
{
2013-01-17 21:15:00 +03:00
case 1 : // creature specialty
2010-07-06 10:32:40 +03:00
{
2013-01-17 21:15:00 +03:00
hs - > growsWithLevel = true ;
2010-07-12 13:20:25 +03:00
2013-01-12 16:53:02 +03:00
const CCreature & specCreature = * VLC - > creh - > creatures [ spec . additionalinfo ] ; //creature in which we have specialty
2010-07-12 13:20:25 +03:00
int creLevel = specCreature . level ;
2012-12-25 20:23:26 +03:00
if ( ! creLevel )
2010-07-07 05:29:07 +03:00
{
2013-01-12 16:53:02 +03:00
if ( spec . additionalinfo = = 146 )
2010-07-07 05:29:07 +03:00
creLevel = 5 ; //treat ballista as 5-level
else
{
2013-04-09 17:31:36 +03:00
logGlobal - > warnStream ( ) < < " Warning: unknown level of " < < specCreature . namePl ;
2010-07-07 05:29:07 +03:00
continue ;
}
}
2013-01-20 19:31:18 +03:00
//bonus->additionalInfo = spec.additionalinfo; //creature id, should not be used again - this works only with limiter
2010-11-20 02:03:31 +02:00
bonus - > limiter . reset ( new CCreatureTypeLimiter ( specCreature , true ) ) ; //with upgrades
2012-07-19 21:52:44 +03:00
bonus - > type = Bonus : : PRIMARY_SKILL ;
2010-11-20 02:03:31 +02:00
bonus - > valType = Bonus : : ADDITIVE_VALUE ;
2010-07-12 13:20:25 +03:00
2010-11-20 02:03:31 +02:00
bonus - > subtype = PrimarySkill : : ATTACK ;
2013-01-17 21:15:00 +03:00
hs - > addNewBonus ( bonus ) ;
2010-07-12 13:20:25 +03:00
2011-02-21 06:13:00 +02:00
bonus = new Bonus ( * bonus ) ;
2010-11-20 02:03:31 +02:00
bonus - > subtype = PrimarySkill : : DEFENSE ;
2013-01-17 21:15:00 +03:00
hs - > addNewBonus ( bonus ) ;
2010-07-13 22:55:13 +03:00
//values will be calculated later
2010-07-12 13:20:25 +03:00
2011-02-21 06:13:00 +02:00
bonus = new Bonus ( * bonus ) ;
2010-11-20 02:03:31 +02:00
bonus - > type = Bonus : : STACKS_SPEED ;
bonus - > val = 1 ; //+1 speed
2013-01-17 21:15:00 +03:00
hs - > addNewBonus ( bonus ) ;
2010-07-06 10:32:40 +03:00
}
break ;
case 2 : //secondary skill
2013-01-17 21:15:00 +03:00
hs - > growsWithLevel = true ;
2010-11-20 02:03:31 +02:00
bonus - > type = Bonus : : SPECIAL_SECONDARY_SKILL ; //needs to be recalculated with level, based on this value
bonus - > valType = Bonus : : BASE_NUMBER ; // to receive nonzero value
2013-01-12 16:53:02 +03:00
bonus - > subtype = spec . subtype ; //skill id
bonus - > val = spec . val ; //value per level, in percent
2013-01-17 21:15:00 +03:00
hs - > addNewBonus ( bonus ) ;
2011-02-21 06:13:00 +02:00
bonus = new Bonus ( * bonus ) ;
2013-01-12 16:53:02 +03:00
switch ( spec . additionalinfo )
2010-07-06 10:32:40 +03:00
{
case 0 : //normal
2010-11-20 02:03:31 +02:00
bonus - > valType = Bonus : : PERCENT_TO_BASE ;
2010-07-06 10:32:40 +03:00
break ;
case 1 : //when it's navigation or there's no 'base' at all
2010-11-20 02:03:31 +02:00
bonus - > valType = Bonus : : PERCENT_TO_ALL ;
2010-07-06 10:32:40 +03:00
break ;
}
2010-11-20 02:03:31 +02:00
bonus - > type = Bonus : : SECONDARY_SKILL_PREMY ; //value will be calculated later
2013-01-17 21:15:00 +03:00
hs - > addNewBonus ( bonus ) ;
2010-07-06 10:32:40 +03:00
break ;
2011-09-24 04:15:36 +03:00
case 3 : //spell damage bonus, level dependent but calculated elsewhere
2010-11-20 02:03:31 +02:00
bonus - > type = Bonus : : SPECIAL_SPELL_LEV ;
2013-01-12 16:53:02 +03:00
bonus - > subtype = spec . subtype ;
2013-01-17 21:15:00 +03:00
hs - > addNewBonus ( bonus ) ;
2010-07-06 10:32:40 +03:00
break ;
case 4 : //creature stat boost
2013-01-12 16:53:02 +03:00
switch ( spec . subtype )
2010-07-08 22:10:26 +03:00
{
case 1 : //attack
2010-11-20 02:03:31 +02:00
bonus - > type = Bonus : : PRIMARY_SKILL ;
bonus - > subtype = PrimarySkill : : ATTACK ;
2010-07-15 22:38:15 +03:00
break ;
2010-07-08 22:10:26 +03:00
case 2 : //defense
2010-11-20 02:03:31 +02:00
bonus - > type = Bonus : : PRIMARY_SKILL ;
bonus - > subtype = PrimarySkill : : DEFENSE ;
2010-07-15 22:38:15 +03:00
break ;
2010-07-17 16:11:12 +03:00
case 3 :
2010-11-20 02:03:31 +02:00
bonus - > type = Bonus : : CREATURE_DAMAGE ;
bonus - > subtype = 0 ; //both min and max
2010-07-15 22:38:15 +03:00
break ;
case 4 : //hp
2010-11-20 02:03:31 +02:00
bonus - > type = Bonus : : STACK_HEALTH ;
2010-07-08 22:10:26 +03:00
break ;
case 5 :
2010-11-20 02:03:31 +02:00
bonus - > type = Bonus : : STACKS_SPEED ;
2010-07-08 22:10:26 +03:00
break ;
default :
2010-07-15 22:38:15 +03:00
continue ;
2010-07-08 22:10:26 +03:00
}
2013-01-20 15:06:18 +03:00
bonus - > additionalInfo = spec . additionalinfo ; //creature id
2010-11-20 02:03:31 +02:00
bonus - > valType = Bonus : : ADDITIVE_VALUE ;
2013-01-12 16:53:02 +03:00
bonus - > limiter . reset ( new CCreatureTypeLimiter ( * VLC - > creh - > creatures [ spec . additionalinfo ] , true ) ) ;
2013-01-17 21:15:00 +03:00
hs - > addNewBonus ( bonus ) ;
2010-07-06 10:32:40 +03:00
break ;
case 5 : //spell damage bonus in percent
2010-11-20 02:03:31 +02:00
bonus - > type = Bonus : : SPECIFIC_SPELL_DAMAGE ;
bonus - > valType = Bonus : : BASE_NUMBER ; // current spell system is screwed
2013-01-12 16:53:02 +03:00
bonus - > subtype = spec . subtype ; //spell id
2013-01-17 21:15:00 +03:00
hs - > addNewBonus ( bonus ) ;
2010-07-06 10:32:40 +03:00
break ;
case 6 : //damage bonus for bless (Adela)
2010-11-20 02:03:31 +02:00
bonus - > type = Bonus : : SPECIAL_BLESS_DAMAGE ;
2013-01-12 16:53:02 +03:00
bonus - > subtype = spec . subtype ; //spell id if you ever wanted to use it otherwise
bonus - > additionalInfo = spec . additionalinfo ; //damage factor
2013-01-17 21:15:00 +03:00
hs - > addNewBonus ( bonus ) ;
2010-07-06 10:32:40 +03:00
break ;
case 7 : //maxed mastery for spell
2010-11-20 02:03:31 +02:00
bonus - > type = Bonus : : MAXED_SPELL ;
2013-01-12 16:53:02 +03:00
bonus - > subtype = spec . subtype ; //spell i
2013-01-17 21:15:00 +03:00
hs - > addNewBonus ( bonus ) ;
2010-07-06 10:32:40 +03:00
break ;
case 8 : //peculiar spells - enchantments
2010-11-20 02:03:31 +02:00
bonus - > type = Bonus : : SPECIAL_PECULIAR_ENCHANT ;
2013-01-12 16:53:02 +03:00
bonus - > subtype = spec . subtype ; //spell id
bonus - > additionalInfo = spec . additionalinfo ; //0, 1 for Coronius
2013-01-17 21:15:00 +03:00
hs - > addNewBonus ( bonus ) ;
2010-07-06 13:02:38 +03:00
break ;
2010-07-06 10:32:40 +03:00
case 9 : //upgrade creatures
2010-07-07 15:20:15 +03:00
{
2013-01-12 16:53:02 +03:00
const auto & creatures = VLC - > creh - > creatures ;
2010-11-20 02:03:31 +02:00
bonus - > type = Bonus : : SPECIAL_UPGRADE ;
2013-01-12 16:53:02 +03:00
bonus - > subtype = spec . subtype ; //base id
bonus - > additionalInfo = spec . additionalinfo ; //target id
2013-01-17 21:15:00 +03:00
hs - > addNewBonus ( bonus ) ;
2011-02-21 06:13:00 +02:00
bonus = new Bonus ( * bonus ) ;
2010-07-17 09:49:16 +03:00
2013-06-29 16:05:48 +03:00
for ( auto cre_id : creatures [ spec . subtype ] - > upgrades )
2010-07-06 10:32:40 +03:00
{
2013-01-12 16:53:02 +03:00
bonus - > subtype = cre_id ; //propagate for regular upgrades of base creature
2013-01-17 21:15:00 +03:00
hs - > addNewBonus ( bonus ) ;
2011-02-21 06:13:00 +02:00
bonus = new Bonus ( * bonus ) ;
2010-07-06 10:32:40 +03:00
}
2011-12-14 00:23:17 +03:00
vstd : : clear_pointer ( bonus ) ;
2010-07-06 10:32:40 +03:00
break ;
2010-07-07 15:20:15 +03:00
}
2010-07-06 10:32:40 +03:00
case 10 : //resource generation
2010-11-20 02:03:31 +02:00
bonus - > type = Bonus : : GENERATE_RESOURCE ;
2013-01-12 16:53:02 +03:00
bonus - > subtype = spec . subtype ;
2013-01-17 21:15:00 +03:00
hs - > addNewBonus ( bonus ) ;
2010-07-06 10:32:40 +03:00
break ;
case 11 : //starting skill with mastery (Adrienne)
2013-02-12 22:49:40 +03:00
cb - > changeSecSkill ( this , SecondarySkill ( spec . val ) , spec . additionalinfo ) ; //simply give it and forget
2010-07-06 10:32:40 +03:00
break ;
case 12 : //army speed
2010-11-20 02:03:31 +02:00
bonus - > type = Bonus : : STACKS_SPEED ;
2013-01-17 21:15:00 +03:00
hs - > addNewBonus ( bonus ) ;
2010-07-06 10:32:40 +03:00
break ;
case 13 : //Dragon bonuses (Mutare)
2010-11-20 02:03:31 +02:00
bonus - > type = Bonus : : PRIMARY_SKILL ;
bonus - > valType = Bonus : : ADDITIVE_VALUE ;
2013-01-12 16:53:02 +03:00
switch ( spec . subtype )
2010-07-16 09:18:41 +03:00
{
case 1 :
2010-11-20 02:03:31 +02:00
bonus - > subtype = PrimarySkill : : ATTACK ;
2010-07-16 09:18:41 +03:00
break ;
case 2 :
2010-11-20 02:03:31 +02:00
bonus - > subtype = PrimarySkill : : DEFENSE ;
2010-07-16 09:18:41 +03:00
break ;
}
2010-11-20 02:03:31 +02:00
bonus - > limiter . reset ( new HasAnotherBonusLimiter ( Bonus : : DRAGON_NATURE ) ) ;
2013-01-17 21:15:00 +03:00
hs - > addNewBonus ( bonus ) ;
2010-07-06 13:02:38 +03:00
break ;
2010-07-06 10:32:40 +03:00
default :
2013-04-09 17:31:36 +03:00
logGlobal - > warnStream ( ) < < " Unexpected hero specialty " < < type ;
2010-07-06 10:32:40 +03:00
}
}
2013-01-17 21:15:00 +03:00
specialty . push_back ( hs ) ; //will it work?
2013-06-29 16:05:48 +03:00
for ( auto hs2 : type - > specialty ) //copy active (probably growing) bonuses from hero prootype to hero object
2013-01-19 20:38:37 +03:00
{
2013-06-29 16:05:48 +03:00
auto hs = new HeroSpecial ( ) ;
2013-01-20 19:31:18 +03:00
attachTo ( hs ) ; //do we ever need to detach it?
2013-01-19 20:38:37 +03:00
hs - > setNodeType ( CBonusSystemNode : : specialty ) ;
2013-06-29 16:05:48 +03:00
for ( auto bonus : hs2 . bonuses )
2013-01-19 20:38:37 +03:00
{
hs - > addNewBonus ( bonus ) ;
}
hs - > growsWithLevel = hs2 . growsWithLevel ;
specialty . push_back ( hs ) ; //will it work?
}
2010-07-17 20:02:11 +03:00
//initialize bonuses
2013-06-29 16:05:48 +03:00
for ( auto skill_info : secSkills )
2013-02-12 22:49:40 +03:00
updateSkill ( SecondarySkill ( skill_info . first ) , skill_info . second ) ;
2013-01-17 21:15:00 +03:00
Updatespecialty ( ) ;
2010-08-15 10:39:07 +03:00
mana = manaLimit ( ) ; //after all bonuses are taken into account, make sure this line is the last one
2011-02-11 14:27:38 +02:00
type - > name = name ;
2010-07-13 22:55:13 +03:00
}
2013-01-17 21:15:00 +03:00
void CGHeroInstance : : Updatespecialty ( ) //TODO: calculate special value of bonuses on-the-fly?
2010-07-13 22:55:13 +03:00
{
2013-06-29 16:05:48 +03:00
for ( auto hs : specialty )
2010-07-13 22:55:13 +03:00
{
2013-01-17 21:15:00 +03:00
if ( hs - > growsWithLevel )
2010-07-13 22:55:13 +03:00
{
2013-01-21 01:49:34 +03:00
//const auto &creatures = VLC->creh->creatures;
2013-01-17 21:15:00 +03:00
2013-06-29 16:05:48 +03:00
for ( Bonus * b : hs - > getBonusList ( ) )
2010-07-13 22:55:13 +03:00
{
2013-01-17 21:15:00 +03:00
switch ( b - > type )
{
case Bonus : : SECONDARY_SKILL_PREMY :
b - > val = ( hs - > valOfBonuses ( Bonus : : SPECIAL_SECONDARY_SKILL , b - > subtype ) * level ) ;
break ; //use only hero skills as bonuses to avoid feedback loop
case Bonus : : PRIMARY_SKILL : //for creatures, that is
2010-07-13 22:55:13 +03:00
{
2013-06-26 14:18:27 +03:00
const CCreature * cre = nullptr ;
2013-01-17 21:15:00 +03:00
int creLevel = 0 ;
2013-01-20 15:06:18 +03:00
if ( auto creatureLimiter = std : : dynamic_pointer_cast < CCreatureTypeLimiter > ( b - > limiter ) ) //TODO: more general eveluation of bonuses?
2010-07-13 22:55:13 +03:00
{
2013-01-20 19:31:18 +03:00
cre = creatureLimiter - > creature ;
creLevel = cre - > level ;
if ( ! creLevel )
2013-01-17 21:15:00 +03:00
{
2013-01-20 15:06:18 +03:00
creLevel = 5 ; //treat ballista as tier 5
2013-01-17 21:15:00 +03:00
}
2010-07-13 22:55:13 +03:00
}
2013-01-20 19:31:18 +03:00
else //no creature found, can't calculate value
2013-01-17 21:15:00 +03:00
{
2013-04-09 17:31:36 +03:00
logGlobal - > warnStream ( ) < < " Primary skill specialty growth supported only with creature type limiters " ;
2010-07-13 22:55:13 +03:00
break ;
2013-01-17 21:15:00 +03:00
}
2013-01-20 15:06:18 +03:00
2013-01-17 21:15:00 +03:00
double primSkillModifier = ( int ) ( level / creLevel ) / 20.0 ;
int param ;
switch ( b - > subtype )
{
case PrimarySkill : : ATTACK :
2013-01-20 19:31:18 +03:00
param = cre - > Attack ( ) ;
2013-01-17 21:15:00 +03:00
break ;
case PrimarySkill : : DEFENSE :
2013-01-20 19:31:18 +03:00
param = cre - > Defense ( ) ;
2013-01-17 21:15:00 +03:00
break ;
default :
2013-01-20 19:31:18 +03:00
continue ;
2013-01-17 21:15:00 +03:00
}
b - > val = ceil ( param * ( 1 + primSkillModifier ) ) - param ; //yep, overcomplicated but matches original
break ;
2010-07-13 22:55:13 +03:00
}
2013-01-17 21:15:00 +03:00
}
2010-07-13 22:55:13 +03:00
}
}
}
2008-12-22 19:48:41 +02:00
}
2013-02-12 22:49:40 +03:00
void CGHeroInstance : : updateSkill ( SecondarySkill which , int val )
2010-07-17 20:02:11 +03:00
{
2013-02-04 22:43:16 +03:00
if ( which = = SecondarySkill : : LEADERSHIP | | which = = SecondarySkill : : LUCK )
2011-02-21 06:13:00 +02:00
{ //luck-> VLC->generaltexth->arraytxt[73+luckSkill]; VLC->generaltexth->arraytxt[104+moraleSkill]
2013-02-04 22:43:16 +03:00
bool luck = which = = SecondarySkill : : LUCK ;
2011-01-06 22:00:19 +02:00
Bonus : : BonusType type [ ] = { Bonus : : MORALE , Bonus : : LUCK } ;
2013-07-02 15:08:30 +03:00
Bonus * b = getBonusLocalFirst ( Selector : : type ( type [ luck ] ) . And ( Selector : : sourceType ( Bonus : : SECONDARY_SKILL ) ) ) ;
2011-01-06 22:00:19 +02:00
if ( ! b )
{
b = new Bonus ( Bonus : : PERMANENT , type [ luck ] , Bonus : : SECONDARY_SKILL , + val , which , which , Bonus : : BASE_NUMBER ) ;
addNewBonus ( b ) ;
}
else
b - > val = + val ;
}
2013-02-04 22:43:16 +03:00
else if ( which = = SecondarySkill : : DIPLOMACY ) //surrender discount: 20% per level
2011-03-05 18:38:22 +02:00
{
2012-07-19 21:52:44 +03:00
2013-07-02 15:08:30 +03:00
if ( Bonus * b = getBonusLocalFirst ( Selector : : type ( Bonus : : SURRENDER_DISCOUNT ) . And ( Selector : : sourceType ( Bonus : : SECONDARY_SKILL ) ) ) )
2011-03-05 18:38:22 +02:00
b - > val = + val ;
else
addNewBonus ( new Bonus ( Bonus : : PERMANENT , Bonus : : SURRENDER_DISCOUNT , Bonus : : SECONDARY_SKILL , val * 20 , which ) ) ;
}
2011-01-06 22:00:19 +02:00
2010-07-17 20:02:11 +03:00
int skillVal = 0 ;
switch ( which )
{
2013-02-04 22:43:16 +03:00
case SecondarySkill : : ARCHERY :
switch ( val )
{
case 1 :
skillVal = 10 ; break ;
case 2 :
skillVal = 25 ; break ;
case 3 :
skillVal = 50 ; break ;
}
break ;
case SecondarySkill : : LOGISTICS :
skillVal = 10 * val ; break ;
case SecondarySkill : : NAVIGATION :
skillVal = 50 * val ; break ;
case SecondarySkill : : MYSTICISM :
skillVal = val ; break ;
case SecondarySkill : : EAGLE_EYE :
skillVal = 30 + 10 * val ; break ;
case SecondarySkill : : NECROMANCY :
skillVal = 10 * val ; break ;
case SecondarySkill : : LEARNING :
skillVal = 5 * val ; break ;
case SecondarySkill : : OFFENCE :
skillVal = 10 * val ; break ;
case SecondarySkill : : ARMORER :
skillVal = 5 * val ; break ;
case SecondarySkill : : INTELLIGENCE :
skillVal = 25 < < ( val - 1 ) ; break ;
case SecondarySkill : : SORCERY :
skillVal = 5 * val ; break ;
case SecondarySkill : : RESISTANCE :
skillVal = 5 < < ( val - 1 ) ; break ;
case SecondarySkill : : FIRST_AID :
skillVal = 25 + 25 * val ; break ;
case SecondarySkill : : ESTATES :
skillVal = 125 < < ( val - 1 ) ; break ;
2010-07-17 20:02:11 +03:00
}
2012-07-19 21:52:44 +03:00
2011-02-12 18:12:48 +02:00
2013-02-02 01:04:25 +03:00
Bonus : : ValueType skillValType = skillVal ? Bonus : : BASE_NUMBER : Bonus : : INDEPENDENT_MIN ;
2013-07-02 15:08:30 +03:00
if ( Bonus * b = getBonusList ( ) . getFirst ( Selector : : typeSubtype ( Bonus : : SECONDARY_SKILL_PREMY , which )
. And ( Selector : : sourceType ( Bonus : : SECONDARY_SKILL ) ) ) ) //only local hero bonus
2010-07-17 20:02:11 +03:00
{
2011-02-12 18:12:48 +02:00
b - > val = skillVal ;
b - > valType = skillValType ;
2010-07-17 20:02:11 +03:00
}
2011-02-12 18:12:48 +02:00
else
{
2013-06-29 16:05:48 +03:00
auto bonus = new Bonus ( Bonus : : PERMANENT , Bonus : : SECONDARY_SKILL_PREMY , Bonus : : SECONDARY_SKILL , skillVal , id . getNum ( ) , which , skillValType ) ;
2011-02-12 18:12:48 +02:00
bonus - > source = Bonus : : SECONDARY_SKILL ;
addNewBonus ( bonus ) ;
}
2012-07-19 21:52:44 +03:00
2010-07-17 20:02:11 +03:00
}
2009-02-20 14:39:27 +02:00
void CGHeroInstance : : setPropertyDer ( ui8 what , ui32 val )
{
2010-05-02 21:20:26 +03:00
if ( what = = ObjProperty : : PRIMARY_STACK_COUNT )
2013-02-16 17:03:47 +03:00
setStackCount ( SlotID ( 0 ) , val ) ;
2009-02-20 14:39:27 +02:00
}
2009-03-12 01:25:59 +02:00
2009-04-12 04:48:50 +03:00
double CGHeroInstance : : getHeroStrength ( ) const
{
2013-02-06 13:16:44 +03:00
return sqrt ( ( 1.0 + 0.05 * getPrimSkillLevel ( PrimarySkill : : ATTACK ) ) * ( 1.0 + 0.05 * getPrimSkillLevel ( PrimarySkill : : DEFENSE ) ) ) ;
2009-04-12 04:48:50 +03:00
}
2011-06-21 12:31:08 +03:00
ui64 CGHeroInstance : : getTotalStrength ( ) const
2009-04-12 04:48:50 +03:00
{
2009-04-16 03:28:54 +03:00
double ret = getHeroStrength ( ) * getArmyStrength ( ) ;
2011-06-21 12:31:08 +03:00
return ( ui64 ) ret ;
2009-04-12 04:48:50 +03:00
}
2012-09-23 21:01:04 +03:00
TExpType CGHeroInstance : : calculateXp ( TExpType exp ) const
2011-02-12 20:48:11 +02:00
{
2013-02-04 22:43:16 +03:00
return exp * ( 100 + valOfBonuses ( Bonus : : SECONDARY_SKILL_PREMY , SecondarySkill : : LEARNING ) ) / 100.0 ;
2011-02-12 20:48:11 +02:00
}
2010-07-21 13:09:29 +03:00
ui8 CGHeroInstance : : getSpellSchoolLevel ( const CSpell * spell , int * outSelectedSchool ) const
2009-04-15 17:03:31 +03:00
{
2010-07-21 13:09:29 +03:00
si16 skill = - 1 ; //skill level
# define TRY_SCHOOL(schoolName, schoolMechanicsId, schoolOutId) \
2010-07-22 03:32:45 +03:00
if ( spell - > schoolName ) \
2010-07-21 13:09:29 +03:00
{ \
2010-12-23 22:18:10 +02:00
int thisSchool = std : : max < int > ( getSecSkillLevel ( \
2013-02-12 22:49:40 +03:00
SecondarySkill ( 14 + ( schoolMechanicsId ) ) ) , \
2010-12-23 22:18:10 +02:00
valOfBonuses ( Bonus : : MAGIC_SCHOOL_SKILL , 1 < < ( schoolMechanicsId ) ) ) ; \
2010-07-21 13:09:29 +03:00
if ( thisSchool > skill ) \
{ \
skill = thisSchool ; \
if ( outSelectedSchool ) \
* outSelectedSchool = schoolOutId ; \
} \
}
TRY_SCHOOL ( fire , 0 , 1 )
TRY_SCHOOL ( air , 1 , 0 )
TRY_SCHOOL ( water , 2 , 2 )
TRY_SCHOOL ( earth , 3 , 3 )
2010-07-28 13:09:15 +03:00
# undef TRY_SCHOOL
2010-07-21 13:09:29 +03:00
2009-07-21 16:53:26 +03:00
2011-12-14 00:23:17 +03:00
vstd : : amax ( skill , valOfBonuses ( Bonus : : MAGIC_SCHOOL_SKILL , 0 ) ) ; //any school bonus
2013-02-11 02:24:57 +03:00
vstd : : amax ( skill , valOfBonuses ( Bonus : : SPELL , spell - > id . toEnum ( ) ) ) ; //given by artifact or other effect
2013-01-17 21:15:00 +03:00
if ( hasBonusOfType ( Bonus : : MAXED_SPELL , spell - > id ) ) //hero specialty (Daremyth, Melodia)
2010-08-29 22:03:10 +03:00
skill = 3 ;
2010-07-21 13:09:29 +03:00
assert ( skill > = 0 & & skill < = 3 ) ;
2009-04-15 17:03:31 +03:00
return skill ;
}
* support for new hero bonuses (BLOCK_MORALE, SECONDARY_SKILL_PREMY (archery), AIR_SPELL_DMG_PREMY, EARTH_SPELL_DMG_PREMY, FIRE_SPELL_DMG_PREMY, WATER_SPELL_DMG_PREMY, BLOCK_SPELLS_ABOVE_LEVEL, SPELL_IMMUNITY, BLOCK_MORALE, FIRE_SPELLS, AIR_SPELLS, WATER_SPELLS, EARTH_SPELLS, SPELL, SPELLS_OF_LEVEL). It means that following artifacts are now supported:
- Orb of the Firmament
- Orb of Silt
- Orb of Tempestuous Fire
- Orb of Driving Rain
- Bow of Elven Cherrywood
- Bowstring of the Unicorn's Mane
- Angel Feather Arrows
- Tome of Fire Magic
- Tome of Air Magic
- Tome of Water Magic
- Tome of Earth Magic
- Recanter's Cloak
- Orb of Inhibition
- Pendant of Dispassion
- Pendant of Second Sight
- Pendant of Holiness
- Pendant of Life
- Pendant of Death
- Pendant of Free Will
- Pendant of Negativity
- Pendant of Total Recall
- Spellbinder's Hat
- Spirit of Oppression
- Sphere of Permanence
I hope I listed them all here :). Please try them and report if something's wrong.
2009-05-03 19:14:16 +03:00
bool CGHeroInstance : : canCastThisSpell ( const CSpell * spell ) const
{
2013-02-07 02:24:43 +03:00
if ( ! getArt ( ArtifactPosition : : SPELLBOOK ) ) //if hero has no spellbook
* support for new hero bonuses (BLOCK_MORALE, SECONDARY_SKILL_PREMY (archery), AIR_SPELL_DMG_PREMY, EARTH_SPELL_DMG_PREMY, FIRE_SPELL_DMG_PREMY, WATER_SPELL_DMG_PREMY, BLOCK_SPELLS_ABOVE_LEVEL, SPELL_IMMUNITY, BLOCK_MORALE, FIRE_SPELLS, AIR_SPELLS, WATER_SPELLS, EARTH_SPELLS, SPELL, SPELLS_OF_LEVEL). It means that following artifacts are now supported:
- Orb of the Firmament
- Orb of Silt
- Orb of Tempestuous Fire
- Orb of Driving Rain
- Bow of Elven Cherrywood
- Bowstring of the Unicorn's Mane
- Angel Feather Arrows
- Tome of Fire Magic
- Tome of Air Magic
- Tome of Water Magic
- Tome of Earth Magic
- Recanter's Cloak
- Orb of Inhibition
- Pendant of Dispassion
- Pendant of Second Sight
- Pendant of Holiness
- Pendant of Life
- Pendant of Death
- Pendant of Free Will
- Pendant of Negativity
- Pendant of Total Recall
- Spellbinder's Hat
- Spirit of Oppression
- Sphere of Permanence
I hope I listed them all here :). Please try them and report if something's wrong.
2009-05-03 19:14:16 +03:00
return false ;
2010-02-10 04:56:00 +02:00
if ( vstd : : contains ( spells , spell - > id ) //hero has this spell in spellbook
2010-05-02 21:20:26 +03:00
| | ( spell - > air & & hasBonusOfType ( Bonus : : AIR_SPELLS ) ) // this is air spell and hero can cast all air spells
| | ( spell - > fire & & hasBonusOfType ( Bonus : : FIRE_SPELLS ) ) // this is fire spell and hero can cast all fire spells
| | ( spell - > water & & hasBonusOfType ( Bonus : : WATER_SPELLS ) ) // this is water spell and hero can cast all water spells
| | ( spell - > earth & & hasBonusOfType ( Bonus : : EARTH_SPELLS ) ) // this is earth spell and hero can cast all earth spells
| | hasBonusOfType ( Bonus : : SPELL , spell - > id )
| | hasBonusOfType ( Bonus : : SPELLS_OF_LEVEL , spell - > level )
* support for new hero bonuses (BLOCK_MORALE, SECONDARY_SKILL_PREMY (archery), AIR_SPELL_DMG_PREMY, EARTH_SPELL_DMG_PREMY, FIRE_SPELL_DMG_PREMY, WATER_SPELL_DMG_PREMY, BLOCK_SPELLS_ABOVE_LEVEL, SPELL_IMMUNITY, BLOCK_MORALE, FIRE_SPELLS, AIR_SPELLS, WATER_SPELLS, EARTH_SPELLS, SPELL, SPELLS_OF_LEVEL). It means that following artifacts are now supported:
- Orb of the Firmament
- Orb of Silt
- Orb of Tempestuous Fire
- Orb of Driving Rain
- Bow of Elven Cherrywood
- Bowstring of the Unicorn's Mane
- Angel Feather Arrows
- Tome of Fire Magic
- Tome of Air Magic
- Tome of Water Magic
- Tome of Earth Magic
- Recanter's Cloak
- Orb of Inhibition
- Pendant of Dispassion
- Pendant of Second Sight
- Pendant of Holiness
- Pendant of Life
- Pendant of Death
- Pendant of Free Will
- Pendant of Negativity
- Pendant of Total Recall
- Spellbinder's Hat
- Spirit of Oppression
- Sphere of Permanence
I hope I listed them all here :). Please try them and report if something's wrong.
2009-05-03 19:14:16 +03:00
)
return true ;
return false ;
}
2009-09-01 01:04:00 +03:00
/**
* Calculates what creatures and how many to be raised from a battle .
* @ param battleResult The results of the battle .
* @ return Returns a pair with the first value indicating the ID of the creature
* type and second value the amount . Both values are returned as - 1 if necromancy
* could not be applied .
*/
2010-11-22 02:34:46 +02:00
CStackBasicDescriptor CGHeroInstance : : calculateNecromancy ( const BattleResult & battleResult ) const
2009-09-01 01:04:00 +03:00
{
2013-02-04 22:43:16 +03:00
const ui8 necromancyLevel = getSecSkillLevel ( SecondarySkill : : NECROMANCY ) ;
2009-09-01 01:04:00 +03:00
2013-07-21 21:27:33 +03:00
// Hero knows necromancy or has Necromancer Cloak
if ( necromancyLevel > 0 | | hasBonusOfType ( Bonus : : IMPROVED_NECROMANCY ) )
2010-05-14 05:18:37 +03:00
{
2013-02-04 22:43:16 +03:00
double necromancySkill = valOfBonuses ( Bonus : : SECONDARY_SKILL_PREMY , SecondarySkill : : NECROMANCY ) / 100.0 ;
2011-12-14 00:23:17 +03:00
vstd : : amin ( necromancySkill , 1.0 ) ; //it's impossible to raise more creatures than all...
2009-09-24 16:23:52 +03:00
const std : : map < ui32 , si32 > & casualties = battleResult . casualties [ ! battleResult . winner ] ;
2009-09-01 01:04:00 +03:00
ui32 raisedUnits = 0 ;
// Figure out what to raise and how many.
2013-02-12 22:49:40 +03:00
const CreatureID creatureTypes [ ] = { CreatureID : : SKELETON , CreatureID : : WALKING_DEAD , CreatureID : : WIGHTS , CreatureID : : LICHES } ;
2010-05-02 21:20:26 +03:00
const bool improvedNecromancy = hasBonusOfType ( Bonus : : IMPROVED_NECROMANCY ) ;
2010-05-14 05:18:37 +03:00
const CCreature * raisedUnitType = VLC - > creh - > creatures [ creatureTypes [ improvedNecromancy ? necromancyLevel : 0 ] ] ;
const ui32 raisedUnitHP = raisedUnitType - > valOfBonuses ( Bonus : : STACK_HEALTH ) ;
2009-09-01 01:04:00 +03:00
2010-05-14 05:18:37 +03:00
//calculate creatures raised from each defeated stack
2013-06-29 16:05:48 +03:00
for ( auto & casualtie : casualties )
2010-05-14 05:18:37 +03:00
{
// Get lost enemy hit points convertible to units.
2013-06-29 16:05:48 +03:00
CCreature * c = VLC - > creh - > creatures [ casualtie . first ] ;
2013-07-21 21:27:33 +03:00
const ui32 raisedHP = c - > valOfBonuses ( Bonus : : STACK_HEALTH ) * casualtie . second * necromancySkill ;
raisedUnits + = std : : min < ui32 > ( raisedHP / raisedUnitHP , casualtie . second * necromancySkill ) ; //limit to % of HP and % of original stack count
2010-05-14 05:18:37 +03:00
}
2009-09-01 01:04:00 +03:00
// Make room for new units.
2013-02-16 17:03:47 +03:00
SlotID slot = getSlotFor ( raisedUnitType - > idNumber ) ;
if ( slot = = SlotID ( ) )
2009-09-24 16:23:52 +03:00
{
2009-09-01 01:04:00 +03:00
// If there's no room for unit, try it's upgraded version 2/3rds the size.
2010-05-02 21:20:26 +03:00
raisedUnitType = VLC - > creh - > creatures [ * raisedUnitType - > upgrades . begin ( ) ] ;
2009-09-01 01:04:00 +03:00
raisedUnits = ( raisedUnits * 2 ) / 3 ;
2010-05-02 21:20:26 +03:00
slot = getSlotFor ( raisedUnitType - > idNumber ) ;
2009-09-01 01:04:00 +03:00
}
if ( raisedUnits < = 0 )
raisedUnits = 1 ;
2010-11-22 02:34:46 +02:00
return CStackBasicDescriptor ( raisedUnitType - > idNumber , raisedUnits ) ;
2009-09-01 01:04:00 +03:00
}
2010-11-22 02:34:46 +02:00
return CStackBasicDescriptor ( ) ;
2009-09-01 01:04:00 +03:00
}
/**
* Show the necromancy dialog with information about units raised .
* @ param raisedStack Pair where the first element represents ID of the raised creature
* and the second element the amount .
*/
2010-11-22 02:34:46 +02:00
void CGHeroInstance : : showNecromancyDialog ( const CStackBasicDescriptor & raisedStack ) const
2009-09-01 01:04:00 +03:00
{
InfoWindow iw ;
2011-06-23 16:50:13 +03:00
iw . soundID = soundBase : : pickup01 + ran ( ) % 7 ;
2009-09-01 01:04:00 +03:00
iw . player = tempOwner ;
2010-04-02 05:07:40 +03:00
iw . components . push_back ( Component ( raisedStack ) ) ;
2009-09-01 01:04:00 +03:00
2010-04-02 05:07:40 +03:00
if ( raisedStack . count > 1 ) // Practicing the dark arts of necromancy, ... (plural)
2012-07-19 21:52:44 +03:00
{
2009-09-01 01:04:00 +03:00
iw . text . addTxt ( MetaString : : GENERAL_TXT , 145 ) ;
2010-04-02 05:07:40 +03:00
iw . text . addReplacement ( raisedStack . count ) ;
2012-07-19 21:52:44 +03:00
}
2010-04-02 05:07:40 +03:00
else // Practicing the dark arts of necromancy, ... (singular)
2012-07-19 21:52:44 +03:00
{
2009-09-01 01:04:00 +03:00
iw . text . addTxt ( MetaString : : GENERAL_TXT , 146 ) ;
}
2013-01-15 17:20:48 +03:00
iw . text . addReplacement ( raisedStack ) ;
2009-09-01 01:04:00 +03:00
cb - > showInfoDialog ( & iw ) ;
}
2009-03-12 01:25:59 +02:00
int3 CGHeroInstance : : getSightCenter ( ) const
{
return getPosition ( false ) ;
}
int CGHeroInstance : : getSightRadious ( ) const
{
2013-02-04 22:43:16 +03:00
return 5 + getSecSkillLevel ( SecondarySkill : : SCOUTING ) + valOfBonuses ( Bonus : : SIGHT_RADIOUS ) ; //default + scouting
2009-04-04 01:34:31 +03:00
}
si32 CGHeroInstance : : manaRegain ( ) const
{
2010-05-02 21:20:26 +03:00
if ( hasBonusOfType ( Bonus : : FULL_MANA_REGENERATION ) )
2009-08-21 22:31:41 +03:00
return manaLimit ( ) ;
2009-08-22 15:50:23 +03:00
2012-07-19 21:52:44 +03:00
return 1 + valOfBonuses ( Bonus : : SECONDARY_SKILL_PREMY , 8 ) + valOfBonuses ( Bonus : : MANA_REGENERATION ) ; //1 + Mysticism level
2009-04-04 01:34:31 +03:00
}
2012-02-17 22:30:40 +03:00
// /**
// * Places an artifact in hero's backpack. If it's a big artifact equips it
// * or discards it if it cannot be equipped.
// */
// void CGHeroInstance::giveArtifact (ui32 aid) //use only for fixed artifacts
// {
// CArtifact * const artifact = VLC->arth->artifacts[aid]; //pointer to constant object
// CArtifactInstance *ai = CArtifactInstance::createNewArtifactInstance(artifact);
// ai->putAt(this, ai->firstAvailableSlot(this));
// }
2009-12-30 17:33:28 +02:00
2010-03-11 01:16:30 +02:00
int CGHeroInstance : : getBoatType ( ) const
{
2012-09-23 21:01:04 +03:00
switch ( type - > heroClass - > getAlignment ( ) )
2010-03-11 01:16:30 +02:00
{
2012-09-23 21:01:04 +03:00
case EAlignment : : GOOD :
return 1 ;
case EAlignment : : EVIL :
return 0 ;
case EAlignment : : NEUTRAL :
2010-03-11 01:16:30 +02:00
return 2 ;
default :
2012-04-22 10:32:45 +03:00
throw std : : runtime_error ( " Wrong alignment! " ) ;
2010-03-11 01:16:30 +02:00
}
}
void CGHeroInstance : : getOutOffsets ( std : : vector < int3 > & offsets ) const
{
static int3 dirs [ ] = { int3 ( 0 , 1 , 0 ) , int3 ( 0 , - 1 , 0 ) , int3 ( - 1 , 0 , 0 ) , int3 ( + 1 , 0 , 0 ) , int3 ( 1 , 1 , 0 ) , int3 ( - 1 , 1 , 0 ) , int3 ( 1 , - 1 , 0 ) , int3 ( - 1 , - 1 , 0 ) } ;
2013-06-29 16:05:48 +03:00
for ( auto & dir : dirs )
offsets + = dir ;
2010-03-11 01:16:30 +02:00
}
int CGHeroInstance : : getSpellCost ( const CSpell * sp ) const
{
return sp - > costs [ getSpellSchoolLevel ( sp ) ] ;
}
2013-02-04 22:43:16 +03:00
void CGHeroInstance : : pushPrimSkill ( PrimarySkill : : PrimarySkill which , int val )
2010-05-02 21:20:26 +03:00
{
2013-02-14 02:55:42 +03:00
addNewBonus ( new Bonus ( Bonus : : PERMANENT , Bonus : : PRIMARY_SKILL , Bonus : : HERO_BASE_SKILL , val , id . getNum ( ) , which ) ) ;
2010-05-02 21:20:26 +03:00
}
2011-12-14 00:23:17 +03:00
EAlignment : : EAlignment CGHeroInstance : : getAlignment ( ) const
2010-07-20 09:05:45 +03:00
{
return type - > heroClass - > getAlignment ( ) ;
}
2010-08-28 17:52:20 +03:00
void CGHeroInstance : : initExp ( )
{
exp = 40 + ( ran ( ) ) % 50 ;
level = 1 ;
}
2010-12-12 01:11:26 +02:00
std : : string CGHeroInstance : : nodeName ( ) const
{
return " Hero " + name ;
}
2013-02-12 22:49:40 +03:00
void CGHeroInstance : : putArtifact ( ArtifactPosition pos , CArtifactInstance * art )
2010-12-30 16:41:46 +02:00
{
assert ( ! getArt ( pos ) ) ;
2012-04-14 05:20:22 +03:00
art - > putAt ( ArtifactLocation ( this , pos ) ) ;
2010-12-30 16:41:46 +02:00
}
void CGHeroInstance : : putInBackpack ( CArtifactInstance * art )
{
putArtifact ( art - > firstBackpackSlot ( this ) , art ) ;
}
2011-01-18 20:56:14 +02:00
bool CGHeroInstance : : hasSpellbook ( ) const
{
2011-12-14 00:23:17 +03:00
return getArt ( ArtifactPosition : : SPELLBOOK ) ;
2011-01-18 20:56:14 +02:00
}
2011-02-04 16:58:14 +02:00
void CGHeroInstance : : deserializationFix ( )
{
2012-04-14 05:20:22 +03:00
artDeserializationFix ( this ) ;
2013-01-20 19:31:18 +03:00
2013-06-29 16:05:48 +03:00
//for (auto hs : specialty)
2013-01-20 19:31:18 +03:00
//{
// attachTo (hs);
//}
2011-02-04 16:58:14 +02:00
}
2011-02-22 11:47:25 +02:00
CBonusSystemNode * CGHeroInstance : : whereShouldBeAttached ( CGameState * gs )
{
if ( visitedTown )
{
if ( inTownGarrison )
return visitedTown ;
else
return & visitedTown - > townAndVis ;
}
else
return CArmedInstance : : whereShouldBeAttached ( gs ) ;
}
2011-09-19 23:50:25 +03:00
int CGHeroInstance : : movementPointsAfterEmbark ( int MPsBefore , int basicCost , bool disembark /*= false*/ ) const
{
if ( hasBonusOfType ( Bonus : : FREE_SHIP_BOARDING ) )
2011-12-14 00:23:17 +03:00
return ( MPsBefore - basicCost ) * static_cast < double > ( maxMovePoints ( disembark ) ) / maxMovePoints ( ! disembark ) ;
2011-09-19 23:50:25 +03:00
return 0 ; //take all MPs otherwise
}
2012-01-03 04:55:26 +03:00
CGHeroInstance : : ECanDig CGHeroInstance : : diggingStatus ( ) const
{
if ( movement < maxMovePoints ( true ) )
return LACK_OF_MOVEMENT ;
2012-11-06 19:39:29 +03:00
else if ( cb - > getTile ( getPosition ( false ) ) - > terType = = ETerrainType : : WATER )
2012-01-03 04:55:26 +03:00
return WRONG_TERRAIN ;
else
{
const TerrainTile * t = cb - > getTile ( getPosition ( ) ) ;
//TODO look for hole
//CGI->mh->getTerrainDescr(h->getPosition(false), hlp, false);
if ( /*hlp.length() || */ t - > blockingObjects . size ( ) > 1 )
return TILE_OCCUPIED ;
else
return CAN_DIG ;
}
}
2013-02-07 20:34:50 +03:00
ArtBearer : : ArtBearer CGHeroInstance : : bearerType ( ) const
2012-04-14 05:20:22 +03:00
{
return ArtBearer : : HERO ;
}
2013-04-20 14:34:01 +03:00
std : : vector < SecondarySkill > CGHeroInstance : : levelUpProposedSkills ( ) const
{
std : : vector < SecondarySkill > skills ;
//picking sec. skills for choice
std : : set < SecondarySkill > basicAndAdv , expert , none ;
for ( int i = 0 ; i < GameConstants : : SKILL_QUANTITY ; i + + )
if ( cb - > isAllowed ( 2 , i ) )
none . insert ( SecondarySkill ( i ) ) ;
2013-06-29 16:05:48 +03:00
for ( auto & elem : secSkills )
2013-04-20 14:34:01 +03:00
{
2013-06-29 16:05:48 +03:00
if ( elem . second < 3 )
basicAndAdv . insert ( elem . first ) ;
2013-04-20 14:34:01 +03:00
else
2013-06-29 16:05:48 +03:00
expert . insert ( elem . first ) ;
none . erase ( elem . first ) ;
2013-04-20 14:34:01 +03:00
}
//first offered skill
if ( basicAndAdv . size ( ) )
{
SecondarySkill s = type - > heroClass - > chooseSecSkill ( basicAndAdv ) ; //upgrade existing
skills . push_back ( s ) ;
basicAndAdv . erase ( s ) ;
}
else if ( none . size ( ) & & canLearnSkill ( ) )
{
skills . push_back ( type - > heroClass - > chooseSecSkill ( none ) ) ; //give new skill
none . erase ( skills . back ( ) ) ;
}
//second offered skill
if ( none . size ( ) & & canLearnSkill ( ) ) //hero have free skill slot
{
skills . push_back ( type - > heroClass - > chooseSecSkill ( none ) ) ; //new skill
}
else if ( basicAndAdv . size ( ) )
{
skills . push_back ( type - > heroClass - > chooseSecSkill ( basicAndAdv ) ) ; //upgrade existing
}
return skills ;
}
bool CGHeroInstance : : gainsLevel ( ) const
{
return exp > = VLC - > heroh - > reqExp ( level + 1 ) ;
}
2009-07-06 22:41:27 +03:00
void CGDwelling : : initObj ( )
{
switch ( ID )
{
2012-09-23 21:01:04 +03:00
case Obj : : CREATURE_GENERATOR1 :
2009-07-09 22:15:22 +03:00
{
2013-02-11 02:24:57 +03:00
CreatureID crid = VLC - > objh - > cregens [ subID ] ;
2010-05-02 21:20:26 +03:00
const CCreature * crs = VLC - > creh - > creatures [ crid ] ;
2009-07-09 22:15:22 +03:00
creatures . resize ( 1 ) ;
creatures [ 0 ] . second . push_back ( crid ) ;
2012-12-19 19:35:58 +03:00
if ( subID > = VLC - > generaltexth - > creGens . size ( ) ) //very messy workaround
{
2013-04-21 15:49:26 +03:00
auto & dwellingNames = VLC - > townh - > factions [ crs - > faction ] - > town - > dwellingNames ;
assert ( ! dwellingNames . empty ( ) ) ;
hoverName = dwellingNames [ VLC - > creh - > creatures [ subID ] - > level - 1 ] ;
2012-12-19 19:35:58 +03:00
}
else
hoverName = VLC - > generaltexth - > creGens [ subID ] ;
2009-07-09 22:15:22 +03:00
if ( crs - > level > 4 )
2013-02-16 17:03:47 +03:00
putStack ( SlotID ( 0 ) , new CStackInstance ( crs , ( crs - > growth ) * 3 ) ) ;
2013-03-03 20:06:03 +03:00
if ( getOwner ( ) ! = PlayerColor : : NEUTRAL )
2009-10-26 11:11:10 +02:00
cb - > gameState ( ) - > players [ getOwner ( ) ] . dwellings . push_back ( this ) ;
2009-07-09 22:15:22 +03:00
}
2009-07-06 22:41:27 +03:00
break ;
2009-07-09 22:15:22 +03:00
2012-09-23 21:01:04 +03:00
case Obj : : CREATURE_GENERATOR4 :
2009-07-06 22:41:27 +03:00
creatures . resize ( 4 ) ;
2009-07-26 13:43:22 +03:00
if ( subID = = 1 ) //Golem Factory
2009-07-06 22:41:27 +03:00
{
2013-02-07 20:34:50 +03:00
creatures [ 0 ] . second . push_back ( CreatureID : : STONE_GOLEM ) ;
creatures [ 1 ] . second . push_back ( CreatureID : : IRON_GOLEM ) ;
creatures [ 2 ] . second . push_back ( CreatureID : : GOLD_GOLEM ) ;
creatures [ 3 ] . second . push_back ( CreatureID : : DIAMOND_GOLEM ) ;
2009-07-26 13:43:22 +03:00
//guards
2013-02-16 17:03:47 +03:00
putStack ( SlotID ( 0 ) , new CStackInstance ( CreatureID : : GOLD_GOLEM , 9 ) ) ;
putStack ( SlotID ( 1 ) , new CStackInstance ( CreatureID : : DIAMOND_GOLEM , 6 ) ) ;
2009-07-06 22:41:27 +03:00
}
2012-07-19 21:52:44 +03:00
else if ( subID = = 0 ) // Elemental Conflux
2009-07-06 22:41:27 +03:00
{
2013-02-07 20:34:50 +03:00
creatures [ 0 ] . second . push_back ( CreatureID : : AIR_ELEMENTAL ) ;
creatures [ 1 ] . second . push_back ( CreatureID : : FIRE_ELEMENTAL ) ;
creatures [ 2 ] . second . push_back ( CreatureID : : EARTH_ELEMENTAL ) ;
creatures [ 3 ] . second . push_back ( CreatureID : : WATER_ELEMENTAL ) ;
2009-07-26 13:43:22 +03:00
//guards
2013-02-16 17:03:47 +03:00
putStack ( SlotID ( 0 ) , new CStackInstance ( CreatureID : : EARTH_ELEMENTAL , 12 ) ) ;
2009-07-06 22:41:27 +03:00
}
else
{
assert ( 0 ) ;
}
2009-07-09 22:15:22 +03:00
hoverName = VLC - > generaltexth - > creGens4 [ subID ] ;
2009-07-06 22:41:27 +03:00
break ;
2009-07-09 22:15:22 +03:00
2012-09-23 21:01:04 +03:00
case Obj : : REFUGEE_CAMP :
2010-07-24 00:05:49 +03:00
//is handled within newturn func
2012-07-19 21:52:44 +03:00
break ;
2010-07-24 00:05:49 +03:00
2012-09-23 21:01:04 +03:00
case Obj : : WAR_MACHINE_FACTORY :
2010-05-15 11:33:32 +03:00
creatures . resize ( 3 ) ;
2013-02-07 20:34:50 +03:00
creatures [ 0 ] . second . push_back ( CreatureID : : BALLISTA ) ;
creatures [ 1 ] . second . push_back ( CreatureID : : FIRST_AID_TENT ) ;
creatures [ 2 ] . second . push_back ( CreatureID : : AMMO_CART ) ;
2010-05-15 11:33:32 +03:00
break ;
2009-07-06 22:41:27 +03:00
default :
assert ( 0 ) ;
break ;
}
}
2013-01-22 00:34:30 +03:00
void CGDwelling : : setProperty ( ui8 what , ui32 val )
2009-10-26 11:11:10 +02:00
{
switch ( what )
{
2010-05-02 21:20:26 +03:00
case ObjProperty : : OWNER : //change owner
2012-09-23 21:01:04 +03:00
if ( ID = = Obj : : CREATURE_GENERATOR1 ) //single generators
2009-10-26 11:11:10 +02:00
{
2013-03-03 20:06:03 +03:00
if ( tempOwner ! = PlayerColor : : NEUTRAL )
2009-10-26 11:11:10 +02:00
{
2010-12-20 23:22:53 +02:00
std : : vector < ConstTransitivePtr < CGDwelling > > * dwellings = & cb - > gameState ( ) - > players [ tempOwner ] . dwellings ;
2009-10-26 11:11:10 +02:00
dwellings - > erase ( std : : find ( dwellings - > begin ( ) , dwellings - > end ( ) , this ) ) ;
}
2013-03-03 20:06:03 +03:00
if ( PlayerColor ( val ) ! = PlayerColor : : NEUTRAL ) //can new owner be neutral?
cb - > gameState ( ) - > players [ PlayerColor ( val ) ] . dwellings . push_back ( this ) ;
2009-10-26 11:11:10 +02:00
}
break ;
2010-07-24 00:05:49 +03:00
case ObjProperty : : AVAILABLE_CREATURE :
creatures . resize ( 1 ) ;
creatures [ 0 ] . second . resize ( 1 ) ;
2013-02-11 02:24:57 +03:00
creatures [ 0 ] . second [ 0 ] = CreatureID ( val ) ;
2010-07-24 00:05:49 +03:00
break ;
2009-10-26 11:11:10 +02:00
}
2010-07-24 00:05:49 +03:00
CGObjectInstance : : setProperty ( what , val ) ;
2009-10-26 11:11:10 +02:00
}
2009-07-06 22:41:27 +03:00
void CGDwelling : : onHeroVisit ( const CGHeroInstance * h ) const
{
2012-09-23 21:01:04 +03:00
if ( ID = = Obj : : REFUGEE_CAMP & & ! creatures [ 0 ] . first ) //Refugee Camp, no available cres
2010-07-24 00:05:49 +03:00
{
InfoWindow iw ;
iw . player = h - > tempOwner ;
iw . text . addTxt ( MetaString : : ADVOB_TXT , 44 ) ; //{%s} \n\n The camp is deserted. Perhaps you should try next week.
iw . text . addReplacement ( MetaString : : OBJ_NAMES , ID ) ;
cb - > sendAndApply ( & iw ) ;
return ;
}
2013-02-09 00:17:39 +03:00
PlayerRelations : : PlayerRelations relations = cb - > gameState ( ) - > getPlayerRelations ( h - > tempOwner , tempOwner ) ;
2012-07-19 21:52:44 +03:00
2013-02-09 00:17:39 +03:00
if ( relations = = PlayerRelations : : ALLIES )
2010-08-06 16:14:10 +03:00
return ; //do not allow recruiting or capturing
2012-07-19 21:52:44 +03:00
2010-08-06 16:14:10 +03:00
if ( ! relations & & stacksCount ( ) > 0 ) //object is guarded, owned by enemy
2009-07-09 22:15:22 +03:00
{
2013-01-12 13:32:03 +03:00
BlockingDialog bd ( true , false ) ;
2009-07-09 22:15:22 +03:00
bd . player = h - > tempOwner ;
bd . text . addTxt ( MetaString : : GENERAL_TXT , 421 ) ; //Much to your dismay, the %s is guarded by %s %s. Do you wish to fight the guards?
2012-09-23 21:01:04 +03:00
bd . text . addReplacement ( ID = = Obj : : CREATURE_GENERATOR1 ? MetaString : : CREGENS : MetaString : : CREGENS4 , subID ) ;
2010-11-22 02:34:46 +02:00
bd . text . addReplacement ( MetaString : : ARRAY_TXT , 176 + Slots ( ) . begin ( ) - > second - > getQuantityID ( ) * 3 ) ;
bd . text . addReplacement ( * Slots ( ) . begin ( ) - > second ) ;
2013-04-20 14:34:01 +03:00
cb - > showBlockingDialog ( & bd ) ;
2009-07-09 22:15:22 +03:00
return ;
}
2012-09-23 21:01:04 +03:00
if ( ! relations & & ID ! = Obj : : WAR_MACHINE_FACTORY )
2009-10-24 22:21:32 +03:00
{
2013-02-09 00:17:39 +03:00
cb - > setOwner ( this , h - > tempOwner ) ;
2009-10-24 22:21:32 +03:00
}
2009-07-06 22:41:27 +03:00
2013-01-12 13:32:03 +03:00
BlockingDialog bd ( true , false ) ;
2009-07-09 22:15:22 +03:00
bd . player = h - > tempOwner ;
2012-09-23 21:01:04 +03:00
if ( ID = = Obj : : CREATURE_GENERATOR1 | | ID = = Obj : : CREATURE_GENERATOR4 )
2010-05-15 11:33:32 +03:00
{
2012-09-23 21:01:04 +03:00
bd . text . addTxt ( MetaString : : ADVOB_TXT , ID = = Obj : : CREATURE_GENERATOR1 ? 35 : 36 ) ; //{%s} Would you like to recruit %s? / {%s} Would you like to recruit %s, %s, %s, or %s?
bd . text . addReplacement ( ID = = Obj : : CREATURE_GENERATOR1 ? MetaString : : CREGENS : MetaString : : CREGENS4 , subID ) ;
2013-06-29 16:05:48 +03:00
for ( auto & elem : creatures )
bd . text . addReplacement ( MetaString : : CRE_PL_NAMES , elem . second [ 0 ] ) ;
2010-05-15 11:33:32 +03:00
}
2012-09-23 21:01:04 +03:00
else if ( ID = = Obj : : REFUGEE_CAMP )
2010-07-24 00:05:49 +03:00
{
bd . text . addTxt ( MetaString : : ADVOB_TXT , 35 ) ; //{%s} Would you like to recruit %s?
bd . text . addReplacement ( MetaString : : OBJ_NAMES , ID ) ;
2013-06-29 16:05:48 +03:00
for ( auto & elem : creatures )
bd . text . addReplacement ( MetaString : : CRE_PL_NAMES , elem . second [ 0 ] ) ;
2010-07-24 00:05:49 +03:00
}
2012-09-23 21:01:04 +03:00
else if ( ID = = Obj : : WAR_MACHINE_FACTORY )
2010-05-15 11:33:32 +03:00
bd . text . addTxt ( MetaString : : ADVOB_TXT , 157 ) ; //{War Machine Factory} Would you like to purchase War Machines?
else
2012-04-22 10:32:45 +03:00
throw std : : runtime_error ( " Illegal dwelling! " ) ;
2009-08-07 01:36:51 +03:00
2013-04-20 14:34:01 +03:00
cb - > showBlockingDialog ( & bd ) ;
2009-07-06 22:41:27 +03:00
}
void CGDwelling : : newTurn ( ) const
{
2013-02-02 11:29:57 +03:00
if ( cb - > getDate ( Date : : DAY_OF_WEEK ) ! = 1 ) //not first day of week
2009-07-06 22:41:27 +03:00
return ;
2010-05-15 11:33:32 +03:00
//town growths and War Machines Factories are handled separately
2012-09-23 21:01:04 +03:00
if ( ID = = Obj : : TOWN | | ID = = Obj : : WAR_MACHINE_FACTORY )
2009-07-31 23:10:22 +03:00
return ;
2009-07-06 22:41:27 +03:00
2012-09-23 21:01:04 +03:00
if ( ID = = Obj : : REFUGEE_CAMP ) //if it's a refugee camp, we need to pick an available creature
2010-07-24 00:05:49 +03:00
{
cb - > setObjProperty ( id , ObjProperty : : AVAILABLE_CREATURE , VLC - > creh - > pickRandomMonster ( ) ) ;
}
2009-07-06 22:41:27 +03:00
bool change = false ;
SetAvailableCreatures sac ;
sac . creatures = creatures ;
sac . tid = id ;
for ( size_t i = 0 ; i < creatures . size ( ) ; i + + )
{
if ( creatures [ i ] . second . size ( ) )
{
2010-08-24 17:26:57 +03:00
CCreature * cre = VLC - > creh - > creatures [ creatures [ i ] . second [ 0 ] ] ;
TQuantity amount = cre - > growth * ( 1 + cre - > valOfBonuses ( Bonus : : CREATURE_GROWTH_PERCENT ) / 100 ) + cre - > valOfBonuses ( Bonus : : CREATURE_GROWTH ) ;
2013-01-29 09:47:20 +03:00
if ( VLC - > modh - > settings . DWELLINGS_ACCUMULATE_CREATURES & & ID ! = Obj : : REFUGEE_CAMP ) //camp should not try to accumulate different kinds of creatures
2010-08-24 17:26:57 +03:00
sac . creatures [ i ] . first + = amount ;
2009-08-07 01:36:51 +03:00
else
2010-08-24 17:26:57 +03:00
sac . creatures [ i ] . first = amount ;
2009-07-06 22:41:27 +03:00
change = true ;
}
}
if ( change )
cb - > sendAndApply ( & sac ) ;
}
2013-04-20 14:34:01 +03:00
void CGDwelling : : heroAcceptsCreatures ( const CGHeroInstance * h ) const
2009-07-09 22:15:22 +03:00
{
2013-02-11 02:24:57 +03:00
CreatureID crid = creatures [ 0 ] . second [ 0 ] ;
2010-05-02 21:20:26 +03:00
CCreature * crs = VLC - > creh - > creatures [ crid ] ;
2010-11-27 22:17:28 +02:00
TQuantity count = creatures [ 0 ] . first ;
2009-07-09 22:15:22 +03:00
2012-09-23 21:01:04 +03:00
if ( crs - > level = = 1 & & ID ! = Obj : : REFUGEE_CAMP ) //first level - creatures are for free
2009-07-09 22:15:22 +03:00
{
2010-11-27 22:17:28 +02:00
if ( count ) //there are available creatures
2009-07-09 22:15:22 +03:00
{
2013-02-16 17:03:47 +03:00
SlotID slot = h - > getSlotFor ( crid ) ;
if ( ! slot . validSlot ( ) ) //no available slot
2009-07-09 22:15:22 +03:00
{
InfoWindow iw ;
iw . player = h - > tempOwner ;
iw . text . addTxt ( MetaString : : GENERAL_TXT , 425 ) ; //The %s would join your hero, but there aren't enough provisions to support them.
iw . text . addReplacement ( MetaString : : CRE_PL_NAMES , crid ) ;
cb - > showInfoDialog ( & iw ) ;
}
else //give creatures
{
SetAvailableCreatures sac ;
sac . tid = id ;
sac . creatures = creatures ;
sac . creatures [ 0 ] . first = 0 ;
InfoWindow iw ;
iw . player = h - > tempOwner ;
iw . text . addTxt ( MetaString : : GENERAL_TXT , 423 ) ; //%d %s join your army.
2010-11-27 22:17:28 +02:00
iw . text . addReplacement ( count ) ;
2009-07-09 22:15:22 +03:00
iw . text . addReplacement ( MetaString : : CRE_PL_NAMES , crid ) ;
cb - > showInfoDialog ( & iw ) ;
cb - > sendAndApply ( & sac ) ;
2010-11-27 22:17:28 +02:00
cb - > addToSlot ( StackLocation ( h , slot ) , crs , count ) ;
2009-07-09 22:15:22 +03:00
}
}
else //there no creatures
{
InfoWindow iw ;
iw . text . addTxt ( MetaString : : GENERAL_TXT , 422 ) ; //There are no %s here to recruit.
iw . text . addReplacement ( MetaString : : CRE_PL_NAMES , crid ) ;
iw . player = h - > tempOwner ;
cb - > sendAndApply ( & iw ) ;
}
}
2009-07-26 13:43:22 +03:00
else
2009-07-09 22:15:22 +03:00
{
2012-09-23 21:01:04 +03:00
if ( ID = = Obj : : WAR_MACHINE_FACTORY ) //pick available War Machines
2010-05-15 11:33:32 +03:00
{
//there is 1 war machine available to recruit if hero doesn't have one
SetAvailableCreatures sac ;
sac . tid = id ;
sac . creatures = creatures ;
2013-02-07 02:24:43 +03:00
sac . creatures [ 0 ] . first = ! h - > getArt ( ArtifactPosition : : MACH1 ) ; //ballista
sac . creatures [ 1 ] . first = ! h - > getArt ( ArtifactPosition : : MACH3 ) ; //first aid tent
sac . creatures [ 2 ] . first = ! h - > getArt ( ArtifactPosition : : MACH2 ) ; //ammo cart
2010-05-15 11:33:32 +03:00
cb - > sendAndApply ( & sac ) ;
}
2009-07-09 22:15:22 +03:00
OpenWindow ow ;
2013-02-14 02:55:42 +03:00
ow . id1 = id . getNum ( ) ;
ow . id2 = h - > id . getNum ( ) ;
2012-09-23 21:01:04 +03:00
ow . window = ( ID = = Obj : : CREATURE_GENERATOR1 | | ID = = Obj : : REFUGEE_CAMP )
2012-07-19 21:52:44 +03:00
? OpenWindow : : RECRUITMENT_FIRST
2009-07-26 13:43:22 +03:00
: OpenWindow : : RECRUITMENT_ALL ;
2009-07-09 22:15:22 +03:00
cb - > sendAndApply ( & ow ) ;
}
}
2013-04-20 14:34:01 +03:00
void CGDwelling : : battleFinished ( const CGHeroInstance * hero , const BattleResult & result ) const
2009-07-09 22:15:22 +03:00
{
2013-04-20 14:34:01 +03:00
if ( result . winner = = 0 )
{
onHeroVisit ( hero ) ;
}
2009-07-09 22:15:22 +03:00
}
2013-04-20 14:34:01 +03:00
void CGDwelling : : blockingDialogAnswered ( const CGHeroInstance * hero , ui32 answer ) const
2009-07-09 22:15:22 +03:00
{
2013-04-20 14:34:01 +03:00
auto relations = cb - > getPlayerRelations ( getOwner ( ) , hero - > getOwner ( ) ) ;
if ( stacksCount ( ) > 0 & & relations = = PlayerRelations : : ENEMIES ) //guards present
2009-07-09 22:15:22 +03:00
{
2013-04-20 14:34:01 +03:00
if ( answer )
cb - > startBattleI ( hero , this ) ;
}
else if ( relations = = PlayerRelations : : SAME_PLAYER & & answer )
{
heroAcceptsCreatures ( hero ) ;
2009-07-09 22:15:22 +03:00
}
}
2009-03-12 01:25:59 +02:00
int CGTownInstance : : getSightRadious ( ) const //returns sight distance
2007-10-27 22:38:48 +03:00
{
2012-09-05 15:49:23 +03:00
if ( subID = = ETownType : : TOWER )
2009-08-24 13:23:44 +03:00
{
2013-02-11 02:24:57 +03:00
if ( hasBuilt ( BuildingID : : GRAIL ) ) //skyship
2009-11-11 19:45:03 +02:00
return - 1 ; //entire map
2013-07-21 21:27:33 +03:00
if ( hasBuilt ( BuildingID : : LOOKOUT_TOWER ) ) //lookout tower
2009-08-23 18:02:21 +03:00
return 20 ;
2009-08-24 13:23:44 +03:00
}
2009-03-12 01:25:59 +02:00
return 5 ;
2007-10-27 22:38:48 +03:00
}
2009-07-09 22:15:22 +03:00
2009-09-21 12:00:33 +03:00
void CGTownInstance : : setPropertyDer ( ui8 what , ui32 val )
{
///this is freakin' overcomplicated solution
switch ( what )
{
2013-02-14 16:19:03 +03:00
case ObjProperty : : STRUCTURE_ADD_VISITING_HERO :
2013-02-14 02:55:42 +03:00
bonusingBuildings [ val ] - > setProperty ( ObjProperty : : VISITORS , visitingHero - > id . getNum ( ) ) ;
2009-09-21 12:00:33 +03:00
break ;
2013-02-14 16:19:03 +03:00
case ObjProperty : : STRUCTURE_CLEAR_VISITORS :
bonusingBuildings [ val ] - > setProperty ( ObjProperty : : STRUCTURE_CLEAR_VISITORS , 0 ) ;
2009-10-06 10:55:39 +03:00
break ;
2013-02-14 16:19:03 +03:00
case ObjProperty : : STRUCTURE_ADD_GARRISONED_HERO : //add garrisoned hero to visitors
2013-02-14 02:55:42 +03:00
bonusingBuildings [ val ] - > setProperty ( ObjProperty : : VISITORS , garrisonHero - > id . getNum ( ) ) ;
2009-12-30 22:49:10 +02:00
break ;
2013-02-14 16:19:03 +03:00
case ObjProperty : : BONUS_VALUE_FIRST :
2010-01-28 18:15:46 +02:00
bonusValue . first = val ;
break ;
2013-02-14 16:19:03 +03:00
case ObjProperty : : BONUS_VALUE_SECOND :
2010-01-28 18:15:46 +02:00
bonusValue . second = val ;
2012-07-19 21:52:44 +03:00
break ;
2009-09-21 12:00:33 +03:00
}
}
2012-03-04 13:43:46 +03:00
CGTownInstance : : EFortLevel CGTownInstance : : fortLevel ( ) const //0 - none, 1 - fort, 2 - citadel, 3 - castle
2008-02-18 23:14:28 +02:00
{
2013-02-11 02:24:57 +03:00
if ( hasBuilt ( BuildingID : : CASTLE ) )
2012-03-04 13:43:46 +03:00
return CASTLE ;
2013-02-11 02:24:57 +03:00
if ( hasBuilt ( BuildingID : : CITADEL ) )
2012-03-04 13:43:46 +03:00
return CITADEL ;
2013-02-11 02:24:57 +03:00
if ( hasBuilt ( BuildingID : : FORT ) )
2012-03-04 13:43:46 +03:00
return FORT ;
return NONE ;
2008-02-18 23:14:28 +02:00
}
2009-07-09 22:15:22 +03:00
2008-02-18 23:14:28 +02:00
int CGTownInstance : : hallLevel ( ) const // -1 - none, 0 - village, 1 - town, 2 - city, 3 - capitol
{
2013-02-11 02:24:57 +03:00
if ( hasBuilt ( BuildingID : : CAPITOL ) )
2008-02-18 23:14:28 +02:00
return 3 ;
2013-02-11 02:24:57 +03:00
if ( hasBuilt ( BuildingID : : CITY_HALL ) )
2008-02-18 23:14:28 +02:00
return 2 ;
2013-02-11 02:24:57 +03:00
if ( hasBuilt ( BuildingID : : TOWN_HALL ) )
2008-02-18 23:14:28 +02:00
return 1 ;
2013-02-11 02:24:57 +03:00
if ( hasBuilt ( BuildingID : : VILLAGE_HALL ) )
2008-02-18 23:14:28 +02:00
return 0 ;
return - 1 ;
}
2008-08-20 09:57:53 +03:00
int CGTownInstance : : mageGuildLevel ( ) const
{
2013-02-11 02:24:57 +03:00
if ( hasBuilt ( BuildingID : : MAGES_GUILD_5 ) )
2008-08-20 09:57:53 +03:00
return 5 ;
2013-02-11 02:24:57 +03:00
if ( hasBuilt ( BuildingID : : MAGES_GUILD_4 ) )
2008-08-20 09:57:53 +03:00
return 4 ;
2013-02-11 02:24:57 +03:00
if ( hasBuilt ( BuildingID : : MAGES_GUILD_3 ) )
2008-08-20 09:57:53 +03:00
return 3 ;
2013-02-11 02:24:57 +03:00
if ( hasBuilt ( BuildingID : : MAGES_GUILD_2 ) )
2008-08-20 09:57:53 +03:00
return 2 ;
2013-02-11 02:24:57 +03:00
if ( hasBuilt ( BuildingID : : MAGES_GUILD_1 ) )
2008-08-20 09:57:53 +03:00
return 1 ;
return 0 ;
}
2012-08-08 00:46:24 +03:00
int CGTownInstance : : creatureDwellingLevel ( int dwelling ) const
2008-04-04 20:30:53 +03:00
{
2012-08-08 00:46:24 +03:00
if ( dwelling < 0 | | dwelling > = GameConstants : : CREATURES_PER_TOWN )
return - 1 ;
for ( int i = 0 ; ; i + + )
{
2013-02-11 22:11:34 +03:00
if ( ! hasBuilt ( BuildingID ( BuildingID : : DWELL_FIRST + dwelling + i * GameConstants : : CREATURES_PER_TOWN ) ) )
2012-08-08 00:46:24 +03:00
return i - 1 ;
}
2008-04-04 20:30:53 +03:00
}
2008-06-03 16:15:34 +03:00
int CGTownInstance : : getHordeLevel ( const int & HID ) const //HID - 0 or 1; returns creature level or -1 if that horde structure is not present
2008-04-04 20:30:53 +03:00
{
2008-04-14 20:45:01 +03:00
return town - > hordeLvl [ HID ] ;
2008-04-04 20:30:53 +03:00
}
2008-06-03 16:15:34 +03:00
int CGTownInstance : : creatureGrowth ( const int & level ) const
2008-04-11 20:41:02 +03:00
{
2011-08-26 23:32:05 +03:00
return getGrowthInfo ( level ) . totalGrowth ( ) ;
}
GrowthInfo CGTownInstance : : getGrowthInfo ( int level ) const
{
GrowthInfo ret ;
2011-12-14 00:23:17 +03:00
if ( level < 0 | | level > = GameConstants : : CREATURES_PER_TOWN )
2011-08-26 23:32:05 +03:00
return ret ;
2013-02-11 22:11:34 +03:00
if ( ! hasBuilt ( BuildingID ( BuildingID : : DWELL_FIRST + level ) ) )
2011-08-26 23:32:05 +03:00
return ret ; //no dwelling
2012-01-13 17:18:32 +03:00
const CCreature * creature = VLC - > creh - > creatures [ creatures [ level ] . second . back ( ) ] ;
2011-08-26 23:32:05 +03:00
const int base = creature - > growth ;
int castleBonus = 0 ;
ret . entries . push_back ( GrowthInfo : : Entry ( VLC - > generaltexth - > allTexts [ 590 ] , base ) ) ; // \n\nBasic growth %d"
2013-02-11 02:24:57 +03:00
if ( hasBuilt ( BuildingID : : CASTLE ) )
ret . entries . push_back ( GrowthInfo : : Entry ( subID , BuildingID : : CASTLE , castleBonus = base ) ) ;
else if ( hasBuilt ( BuildingID : : CITADEL ) )
ret . entries . push_back ( GrowthInfo : : Entry ( subID , BuildingID : : CITADEL , castleBonus = base / 2 ) ) ;
2011-08-26 23:32:05 +03:00
if ( town - > hordeLvl [ 0 ] = = level ) //horde 1
2013-02-11 02:24:57 +03:00
if ( hasBuilt ( BuildingID : : HORDE_1 ) )
ret . entries . push_back ( GrowthInfo : : Entry ( subID , BuildingID : : HORDE_1 , creature - > hordeGrowth ) ) ;
2011-08-26 23:32:05 +03:00
if ( town - > hordeLvl [ 1 ] = = level ) //horde 2
2013-02-11 02:24:57 +03:00
if ( hasBuilt ( BuildingID : : HORDE_2 ) )
ret . entries . push_back ( GrowthInfo : : Entry ( subID , BuildingID : : HORDE_2 , creature - > hordeGrowth ) ) ;
2011-08-26 23:32:05 +03:00
int dwellingBonus = 0 ;
if ( const PlayerState * p = cb - > getPlayer ( tempOwner , false ) )
2010-06-21 07:43:10 +03:00
{
2013-06-29 16:05:48 +03:00
for ( const CGDwelling * dwelling : p - > dwellings )
2012-01-13 17:18:32 +03:00
if ( vstd : : contains ( creatures [ level ] . second , dwelling - > creatures [ 0 ] . second [ 0 ] ) )
2011-08-26 23:32:05 +03:00
dwellingBonus + + ;
2010-06-21 07:43:10 +03:00
}
2009-08-16 16:44:17 +03:00
2011-08-26 23:32:05 +03:00
if ( dwellingBonus )
ret . entries . push_back ( GrowthInfo : : Entry ( VLC - > generaltexth - > allTexts [ 591 ] , dwellingBonus ) ) ; // \nExternal dwellings %+d
2012-07-19 21:52:44 +03:00
2011-08-26 23:32:05 +03:00
//other *-of-legion-like bonuses (%d to growth cumulative with grail)
2013-07-02 15:08:30 +03:00
TBonusListPtr bonuses = getBonuses ( Selector : : type ( Bonus : : CREATURE_GROWTH ) . And ( Selector : : subtype ( level ) ) ) ;
2013-06-29 16:05:48 +03:00
for ( const Bonus * b : * bonuses )
2011-08-26 23:32:05 +03:00
ret . entries . push_back ( GrowthInfo : : Entry ( b - > Description ( ) + " %+d " , b - > val ) ) ;
//statue-of-legion-like bonus: % to base+castle
2011-09-06 16:59:26 +03:00
TBonusListPtr bonuses2 = getBonuses ( Selector : : type ( Bonus : : CREATURE_GROWTH_PERCENT ) ) ;
2013-06-29 16:05:48 +03:00
for ( const Bonus * b : * bonuses2 )
2011-08-26 23:32:05 +03:00
ret . entries . push_back ( GrowthInfo : : Entry ( b - > Description ( ) + " %+d " , b - > val * ( base + castleBonus ) / 100 ) ) ;
2013-02-11 02:24:57 +03:00
if ( hasBuilt ( BuildingID : : GRAIL ) ) //grail - +50% to ALL (so far added) growth
ret . entries . push_back ( GrowthInfo : : Entry ( subID , BuildingID : : GRAIL , ret . totalGrowth ( ) / 2 ) ) ;
2011-08-26 23:32:05 +03:00
return ret ;
2008-04-11 20:41:02 +03:00
}
2011-08-26 23:32:05 +03:00
2008-02-18 23:14:28 +02:00
int CGTownInstance : : dailyIncome ( ) const
{
int ret = 0 ;
2013-02-11 02:24:57 +03:00
if ( hasBuilt ( BuildingID : : GRAIL ) )
2008-02-18 23:14:28 +02:00
ret + = 5000 ;
2012-09-05 15:49:23 +03:00
2013-02-11 02:24:57 +03:00
if ( hasBuilt ( BuildingID : : CAPITOL ) )
2008-02-18 23:14:28 +02:00
ret + = 4000 ;
2013-02-11 02:24:57 +03:00
else if ( hasBuilt ( BuildingID : : CITY_HALL ) )
2008-02-18 23:14:28 +02:00
ret + = 2000 ;
2013-02-11 02:24:57 +03:00
else if ( hasBuilt ( BuildingID : : TOWN_HALL ) )
2008-02-18 23:14:28 +02:00
ret + = 1000 ;
2013-02-11 02:24:57 +03:00
else if ( hasBuilt ( BuildingID : : VILLAGE_HALL ) )
2008-02-18 23:14:28 +02:00
ret + = 500 ;
return ret ;
}
2008-01-09 19:21:31 +02:00
bool CGTownInstance : : hasFort ( ) const
{
2013-02-11 02:24:57 +03:00
return hasBuilt ( BuildingID : : FORT ) ;
2008-01-09 19:21:31 +02:00
}
2008-02-05 05:56:45 +02:00
bool CGTownInstance : : hasCapitol ( ) const
{
2013-02-11 02:24:57 +03:00
return hasBuilt ( BuildingID : : CAPITOL ) ;
2008-02-05 05:56:45 +02:00
}
2007-10-27 22:38:48 +03:00
CGTownInstance : : CGTownInstance ( )
2013-01-06 22:30:12 +03:00
: IShipyard ( this ) , IMarket ( this ) , town ( nullptr ) , builded ( 0 ) , destroyed ( 0 ) , identifier ( 0 ) , alignment ( 0xff )
2007-10-27 22:38:48 +03:00
{
2013-01-06 22:30:12 +03:00
2007-10-27 22:38:48 +03:00
}
2008-12-22 19:48:41 +02:00
CGTownInstance : : ~ CGTownInstance ( )
2009-09-23 15:42:14 +03:00
{
2013-06-29 16:05:48 +03:00
for ( auto & elem : bonusingBuildings )
delete elem ;
2009-09-23 15:42:14 +03:00
}
2008-12-22 19:48:41 +02:00
int CGTownInstance : : spellsAtLevel ( int level , bool checkGuild ) const
2007-10-27 22:38:48 +03:00
{
2008-12-22 19:48:41 +02:00
if ( checkGuild & & mageGuildLevel ( ) < level )
return 0 ;
int ret = 6 - level ; //how many spells are available at this level
2012-09-05 15:49:23 +03:00
2013-02-11 02:24:57 +03:00
if ( hasBuilt ( BuildingID : : LIBRARY , ETownType : : TOWER ) )
2012-07-19 21:52:44 +03:00
ret + + ;
2012-09-05 15:49:23 +03:00
2008-12-22 19:48:41 +02:00
return ret ;
2007-10-27 22:38:48 +03:00
}
2008-12-22 19:48:41 +02:00
bool CGTownInstance : : needsLastStack ( ) const
2007-10-27 22:38:48 +03:00
{
2008-12-22 19:48:41 +02:00
if ( garrisonHero )
return true ;
else return false ;
2007-10-27 22:38:48 +03:00
}
2008-12-22 19:48:41 +02:00
2008-12-27 03:01:59 +02:00
void CGTownInstance : : onHeroVisit ( const CGHeroInstance * h ) const
2008-02-07 20:45:22 +02:00
{
2010-08-13 13:46:08 +03:00
if ( ! cb - > gameState ( ) - > getPlayerRelations ( getOwner ( ) , h - > getOwner ( ) ) ) //if this is enemy
2008-12-22 19:48:41 +02:00
{
2011-02-21 06:13:00 +02:00
if ( armedGarrison ( ) | | visitingHero )
2009-08-22 16:59:15 +03:00
{
2013-06-26 14:18:27 +03:00
const CGHeroInstance * defendingHero = nullptr ;
2011-02-21 06:13:00 +02:00
const CArmedInstance * defendingArmy = this ;
2009-08-22 16:59:15 +03:00
if ( visitingHero )
defendingHero = visitingHero ;
else if ( garrisonHero )
defendingHero = garrisonHero ;
if ( defendingHero )
defendingArmy = defendingHero ;
bool outsideTown = ( defendingHero = = visitingHero & & garrisonHero ) ;
2011-02-21 06:13:00 +02:00
2012-07-19 21:52:44 +03:00
//TODO
//"borrowing" army from garrison to visiting hero
2011-02-21 06:13:00 +02:00
2013-06-26 14:18:27 +03:00
cb - > startBattlePrimary ( h , defendingArmy , getSightCenter ( ) , h , defendingHero , false , ( outsideTown ? nullptr : this ) ) ;
2009-08-22 16:59:15 +03:00
}
else
{
2013-02-09 00:17:39 +03:00
cb - > setOwner ( this , h - > tempOwner ) ;
2011-02-21 06:13:00 +02:00
removeCapitols ( h - > getOwner ( ) ) ;
2013-02-09 00:17:39 +03:00
cb - > heroVisitCastle ( this , h ) ;
2009-08-22 16:59:15 +03:00
}
2008-12-22 19:48:41 +02:00
}
2013-04-20 21:44:55 +03:00
else if ( h - > visitablePos ( ) = = visitablePos ( ) )
2012-07-17 11:52:27 +03:00
{
if ( h - > commander & & ! h - > commander - > alive ) //rise commander. TODO: interactive script
{
SetCommanderProperty scp ;
scp . heroid = h - > id ;
scp . which = SetCommanderProperty : : ALIVE ;
scp . amount = 1 ;
cb - > sendAndApply ( & scp ) ;
}
2013-02-09 00:17:39 +03:00
cb - > heroVisitCastle ( this , h ) ;
2012-07-17 11:52:27 +03:00
}
2013-04-20 21:44:55 +03:00
else
{
logGlobal - > errorStream ( ) < < h - > name < < " visits allied town of " < < name < < " from different pos? " ;
}
2008-10-26 22:58:34 +02:00
}
2008-12-27 03:01:59 +02:00
void CGTownInstance : : onHeroLeave ( const CGHeroInstance * h ) const
2008-10-26 22:58:34 +02:00
{
2013-02-09 00:17:39 +03:00
cb - > stopHeroVisitCastle ( this , h ) ;
2008-10-26 22:58:34 +02:00
}
2008-12-22 19:48:41 +02:00
void CGTownInstance : : initObj ( )
2010-06-07 08:28:12 +03:00
///initialize town structures
{
2010-02-01 19:07:46 +02:00
blockVisit = true ;
2013-04-21 15:49:26 +03:00
hoverName = name + " , " + town - > faction - > name ;
2009-07-06 22:41:27 +03:00
2012-09-05 15:49:23 +03:00
if ( subID = = ETownType : : DUNGEON )
2011-12-14 00:23:17 +03:00
creatures . resize ( GameConstants : : CREATURES_PER_TOWN + 1 ) ; //extra dwelling for Dungeon
2010-07-10 19:50:23 +03:00
else
2011-12-14 00:23:17 +03:00
creatures . resize ( GameConstants : : CREATURES_PER_TOWN ) ;
for ( int i = 0 ; i < GameConstants : : CREATURES_PER_TOWN ; i + + )
2009-07-06 22:41:27 +03:00
{
2012-08-08 00:46:24 +03:00
int dwellingLevel = creatureDwellingLevel ( i ) ;
int creaturesTotal = town - > creatures [ i ] . size ( ) ;
for ( int j = 0 ; j < std : : min ( dwellingLevel + 1 , creaturesTotal ) ; j + + )
creatures [ i ] . second . push_back ( town - > creatures [ i ] [ j ] ) ;
2009-07-06 22:41:27 +03:00
}
2010-07-10 19:50:23 +03:00
2009-09-21 12:00:33 +03:00
switch ( subID )
2009-08-23 18:02:21 +03:00
{ //add new visitable objects
2009-10-05 19:38:54 +03:00
case 0 :
2013-02-11 22:11:34 +03:00
bonusingBuildings . push_back ( new COPWBonus ( BuildingID : : STABLES , this ) ) ;
2009-10-05 19:38:54 +03:00
break ;
2010-07-10 19:50:23 +03:00
case 5 :
2013-02-11 22:11:34 +03:00
bonusingBuildings . push_back ( new COPWBonus ( BuildingID : : MANA_VORTEX , this ) ) ;
2010-07-10 19:50:23 +03:00
case 2 : case 3 : case 6 :
2013-02-11 22:11:34 +03:00
bonusingBuildings . push_back ( new CTownBonus ( BuildingID : : SPECIAL_4 , this ) ) ;
2009-08-23 18:02:21 +03:00
break ;
case 7 :
2013-02-11 22:11:34 +03:00
bonusingBuildings . push_back ( new CTownBonus ( BuildingID : : SPECIAL_1 , this ) ) ;
2009-08-23 18:02:21 +03:00
break ;
2010-06-13 16:59:59 +03:00
}
//add special bonuses from buildings
2011-02-04 16:58:14 +02:00
recreateBuildingsBonuses ( ) ;
2008-12-22 19:48:41 +02:00
}
2009-10-06 10:55:39 +03:00
void CGTownInstance : : newTurn ( ) const
{
2013-02-02 11:29:57 +03:00
if ( cb - > getDate ( Date : : DAY_OF_WEEK ) = = 1 ) //reset on new week
2009-10-06 10:55:39 +03:00
{
2012-09-05 15:49:23 +03:00
//give resources for Rampart, Mystic Pond
2013-02-11 02:24:57 +03:00
if ( hasBuilt ( BuildingID : : MYSTIC_POND , ETownType : : RAMPART )
2013-03-03 20:06:03 +03:00
& & cb - > getDate ( Date : : DAY ) ! = 1 & & ( tempOwner < PlayerColor : : PLAYER_LIMIT ) )
2010-01-28 18:15:46 +02:00
{
int resID = rand ( ) % 4 + 2 ; //bonus to random rare resource
resID = ( resID = = 2 ) ? 1 : resID ;
int resVal = rand ( ) % 4 + 1 ; //with size 1..4
2013-02-04 22:43:16 +03:00
cb - > giveResource ( tempOwner , static_cast < Res : : ERes > ( resID ) , resVal ) ;
2013-02-14 16:19:03 +03:00
cb - > setObjProperty ( id , ObjProperty : : BONUS_VALUE_FIRST , resID ) ;
cb - > setObjProperty ( id , ObjProperty : : BONUS_VALUE_SECOND , resVal ) ;
2010-01-28 18:15:46 +02:00
}
2012-09-05 15:49:23 +03:00
if ( subID = = ETownType : : DUNGEON )
2013-06-29 16:05:48 +03:00
for ( auto & elem : bonusingBuildings )
2010-01-01 14:15:20 +02:00
{
2013-06-29 16:05:48 +03:00
if ( ( elem ) - > ID = = BuildingID : : MANA_VORTEX )
cb - > setObjProperty ( id , ObjProperty : : STRUCTURE_CLEAR_VISITORS , ( elem ) - > id ) ; //reset visitors for Mana Vortex
2010-01-01 14:15:20 +02:00
}
2010-06-29 12:59:14 +03:00
2013-03-03 20:06:03 +03:00
if ( tempOwner = = PlayerColor : : NEUTRAL ) //garrison growth for neutral towns
2010-06-29 12:59:14 +03:00
{
2013-02-16 17:03:47 +03:00
std : : vector < SlotID > nativeCrits ; //slots
2013-06-29 16:05:48 +03:00
for ( auto & elem : Slots ( ) )
2010-06-29 12:59:14 +03:00
{
2013-06-29 16:05:48 +03:00
if ( elem . second - > type - > faction = = subID ) //native
2010-06-29 12:59:14 +03:00
{
2013-06-29 16:05:48 +03:00
nativeCrits . push_back ( elem . first ) ; //collect matching slots
2010-06-29 12:59:14 +03:00
}
}
if ( nativeCrits . size ( ) )
{
2013-02-16 17:03:47 +03:00
SlotID pos = nativeCrits [ rand ( ) % nativeCrits . size ( ) ] ;
2010-11-27 03:46:19 +02:00
StackLocation sl ( this , pos ) ;
2010-11-22 02:34:46 +02:00
const CCreature * c = getCreature ( pos ) ;
2011-09-24 04:15:36 +03:00
if ( rand ( ) % 100 < 90 | | c - > upgrades . empty ( ) ) //increase number if no upgrade available
2010-06-29 12:59:14 +03:00
{
2010-11-27 03:46:19 +02:00
cb - > changeStackCount ( sl , c - > growth ) ;
2010-06-29 12:59:14 +03:00
}
else //upgrade
{
2010-11-27 03:46:19 +02:00
cb - > changeStackType ( sl , VLC - > creh - > creatures [ * c - > upgrades . begin ( ) ] ) ;
2010-06-29 12:59:14 +03:00
}
}
2011-12-14 00:23:17 +03:00
if ( ( stacksCount ( ) < GameConstants : : ARMY_SIZE & & rand ( ) % 100 < 25 ) | | Slots ( ) . empty ( ) ) //add new stack
2010-06-29 12:59:14 +03:00
{
2013-02-02 11:29:57 +03:00
int i = rand ( ) % std : : min ( GameConstants : : ARMY_SIZE , cb - > getDate ( Date : : MONTH ) < < 1 ) ;
2013-02-11 02:24:57 +03:00
CreatureID c = town - > creatures [ i ] [ 0 ] ;
2013-02-16 17:03:47 +03:00
SlotID n ;
2012-07-19 21:52:44 +03:00
2010-11-27 03:46:19 +02:00
TQuantity count = creatureGrowth ( i ) ;
2011-05-29 15:36:38 +03:00
if ( ! count ) // no dwelling
count = VLC - > creh - > creatures [ c ] - > growth ;
2010-11-27 03:46:19 +02:00
2010-06-29 12:59:14 +03:00
{ //no lower tiers or above current month
2013-02-16 17:03:47 +03:00
if ( ( n = getSlotFor ( c ) ) . validSlot ( ) )
2012-07-19 21:52:44 +03:00
{
2010-11-27 03:46:19 +02:00
StackLocation sl ( this , n ) ;
2010-06-29 12:59:14 +03:00
if ( slotEmpty ( n ) )
2010-11-27 03:46:19 +02:00
cb - > insertNewStack ( sl , VLC - > creh - > creatures [ c ] , count ) ;
else //add to existing
cb - > changeStackCount ( sl , count ) ;
2010-06-29 12:59:14 +03:00
}
}
2012-07-19 21:52:44 +03:00
}
2010-06-29 12:59:14 +03:00
}
2009-10-06 10:55:39 +03:00
}
}
2010-01-28 18:15:46 +02:00
2009-03-12 01:25:59 +02:00
int3 CGTownInstance : : getSightCenter ( ) const
{
return pos - int3 ( 2 , 0 , 0 ) ;
}
2010-02-13 06:47:31 +02:00
ui8 CGTownInstance : : getPassableness ( ) const
{
2011-02-21 06:13:00 +02:00
if ( ! armedGarrison ( ) ) //empty castle - anyone can visit
2011-12-14 00:23:17 +03:00
return GameConstants : : ALL_PLAYERS ;
2013-03-03 20:06:03 +03:00
if ( tempOwner = = PlayerColor : : NEUTRAL ) //neutral guarded - no one can visit
2010-08-06 16:14:10 +03:00
return 0 ;
2012-07-19 21:52:44 +03:00
2010-08-08 17:39:41 +03:00
ui8 mask = 0 ;
2010-08-06 16:14:10 +03:00
TeamState * ts = cb - > gameState ( ) - > getPlayerTeam ( tempOwner ) ;
2013-06-29 16:05:48 +03:00
for ( PlayerColor it : ts - > players )
2013-03-03 20:06:03 +03:00
mask | = 1 < < it . getNum ( ) ; //allies - add to possible visitors
2012-07-19 21:52:44 +03:00
2010-08-06 16:14:10 +03:00
return mask ;
2010-02-13 06:47:31 +02:00
}
2009-07-26 06:33:13 +03:00
void CGTownInstance : : getOutOffsets ( std : : vector < int3 > & offsets ) const
{
2009-09-20 15:47:40 +03:00
offsets + = int3 ( - 1 , 2 , 0 ) , int3 ( - 3 , 2 , 0 ) ;
2009-07-26 06:33:13 +03:00
}
2013-03-03 20:06:03 +03:00
void CGTownInstance : : removeCapitols ( PlayerColor owner ) const
2012-07-19 21:52:44 +03:00
{
2010-02-28 08:36:51 +02:00
if ( hasCapitol ( ) ) // search if there's an older capitol
2012-07-19 21:52:44 +03:00
{
2009-10-06 09:15:56 +03:00
PlayerState * state = cb - > gameState ( ) - > getPlayer ( owner ) ; //get all towns owned by player
2013-03-03 20:06:03 +03:00
for ( auto i = state - > towns . cbegin ( ) ; i < state - > towns . cend ( ) ; + + i )
2012-07-19 21:52:44 +03:00
{
if ( * i ! = this & & ( * i ) - > hasCapitol ( ) )
{
RazeStructures rs ;
rs . tid = id ;
2013-02-11 22:11:34 +03:00
rs . bid . insert ( BuildingID : : CAPITOL ) ;
2012-07-19 21:52:44 +03:00
rs . destroyed = destroyed ;
cb - > sendAndApply ( & rs ) ;
return ;
}
}
}
}
2009-09-23 15:42:14 +03:00
2010-02-13 06:47:31 +02:00
int CGTownInstance : : getBoatType ( ) const
2010-02-01 19:07:46 +02:00
{
2013-04-21 15:49:26 +03:00
switch ( town - > faction - > alignment )
2013-03-14 23:44:00 +03:00
{
case EAlignment : : EVIL : return 0 ;
case EAlignment : : GOOD : return 1 ;
case EAlignment : : NEUTRAL : return 2 ;
}
2013-04-02 20:06:43 +03:00
assert ( 0 ) ;
return - 1 ;
2010-02-01 19:07:46 +02:00
}
2010-05-18 10:01:54 +03:00
int CGTownInstance : : getMarketEfficiency ( ) const
{
2013-02-11 02:24:57 +03:00
if ( ! hasBuilt ( BuildingID : : MARKETPLACE ) )
2010-05-18 10:01:54 +03:00
return 0 ;
2011-05-10 01:20:47 +03:00
const PlayerState * p = cb - > getPlayer ( tempOwner ) ;
2010-05-18 10:01:54 +03:00
assert ( p ) ;
int marketCount = 0 ;
2013-06-29 16:05:48 +03:00
for ( const CGTownInstance * t : p - > towns )
2013-02-11 02:24:57 +03:00
if ( t - > hasBuilt ( BuildingID : : MARKETPLACE ) )
2010-05-18 10:01:54 +03:00
marketCount + + ;
return marketCount ;
}
2011-12-14 00:23:17 +03:00
bool CGTownInstance : : allowsTrade ( EMarketMode : : EMarketMode mode ) const
2010-05-18 10:01:54 +03:00
{
switch ( mode )
{
2011-12-14 00:23:17 +03:00
case EMarketMode : : RESOURCE_RESOURCE :
case EMarketMode : : RESOURCE_PLAYER :
2013-02-11 02:24:57 +03:00
return hasBuilt ( BuildingID : : MARKETPLACE ) ;
2012-09-05 15:49:23 +03:00
2011-12-14 00:23:17 +03:00
case EMarketMode : : ARTIFACT_RESOURCE :
case EMarketMode : : RESOURCE_ARTIFACT :
2013-02-11 02:24:57 +03:00
return hasBuilt ( BuildingID : : ARTIFACT_MERCHANT , ETownType : : TOWER )
| | hasBuilt ( BuildingID : : ARTIFACT_MERCHANT , ETownType : : DUNGEON )
| | hasBuilt ( BuildingID : : ARTIFACT_MERCHANT , ETownType : : CONFLUX ) ;
2012-09-05 15:49:23 +03:00
2011-12-14 00:23:17 +03:00
case EMarketMode : : CREATURE_RESOURCE :
2013-02-11 02:24:57 +03:00
return hasBuilt ( BuildingID : : FREELANCERS_GUILD , ETownType : : STRONGHOLD ) ;
2012-09-05 15:49:23 +03:00
2011-12-14 00:23:17 +03:00
case EMarketMode : : CREATURE_UNDEAD :
2013-02-11 02:24:57 +03:00
return hasBuilt ( BuildingID : : SKELETON_TRANSFORMER , ETownType : : NECROPOLIS ) ;
2012-09-05 15:49:23 +03:00
2011-12-14 00:23:17 +03:00
case EMarketMode : : RESOURCE_SKILL :
2013-02-11 02:24:57 +03:00
return hasBuilt ( BuildingID : : MAGIC_UNIVERSITY , ETownType : : CONFLUX ) ;
2010-05-18 10:01:54 +03:00
default :
assert ( 0 ) ;
return false ;
}
}
2011-12-14 00:23:17 +03:00
std : : vector < int > CGTownInstance : : availableItemsIds ( EMarketMode : : EMarketMode mode ) const
2010-06-27 19:03:01 +03:00
{
2011-12-14 00:23:17 +03:00
if ( mode = = EMarketMode : : RESOURCE_ARTIFACT )
2010-06-27 19:03:01 +03:00
{
std : : vector < int > ret ;
2013-06-29 16:05:48 +03:00
for ( const CArtifact * a : merchantArtifacts )
2010-06-27 19:03:01 +03:00
if ( a )
ret . push_back ( a - > id ) ;
else
ret . push_back ( - 1 ) ;
return ret ;
}
2011-12-14 00:23:17 +03:00
else if ( mode = = EMarketMode : : RESOURCE_SKILL )
2010-07-20 17:08:13 +03:00
{
return universitySkills ;
}
2010-06-27 19:03:01 +03:00
else
return IMarket : : availableItemsIds ( mode ) ;
}
2011-02-04 16:58:14 +02:00
std : : string CGTownInstance : : nodeName ( ) const
{
2013-04-21 15:49:26 +03:00
return " Town ( " + ( town ? town - > faction - > name : " unknown " ) + " ) of " + name ;
2011-02-04 16:58:14 +02:00
}
void CGTownInstance : : deserializationFix ( )
{
attachTo ( & townAndVis ) ;
2013-04-20 21:44:55 +03:00
//Hero is already handled by CGameState::attachArmedObjects
// if(visitingHero)
// visitingHero->attachTo(&townAndVis);
// if(garrisonHero)
// garrisonHero->attachTo(this);
2011-02-04 16:58:14 +02:00
}
2013-04-27 11:11:20 +03:00
void CGTownInstance : : updateMoraleBonusFromArmy ( )
{
2013-07-02 15:08:30 +03:00
Bonus * b = getBonusList ( ) . getFirst ( Selector : : sourceType ( Bonus : : ARMY ) . And ( Selector : : type ( Bonus : : MORALE ) ) ) ;
2013-04-27 11:11:20 +03:00
if ( ! b )
{
b = new Bonus ( Bonus : : PERMANENT , Bonus : : MORALE , Bonus : : ARMY , 0 , - 1 ) ;
addNewBonus ( b ) ;
}
if ( garrisonHero )
b - > val = 0 ;
else
CArmedInstance : : updateMoraleBonusFromArmy ( ) ;
}
2011-02-04 16:58:14 +02:00
void CGTownInstance : : recreateBuildingsBonuses ( )
{
2013-04-21 15:49:26 +03:00
static TPropagatorPtr playerProp ( new CPropagatorNodeType ( PLAYER ) ) ;
2012-03-06 19:59:55 +03:00
BonusList bl ;
2011-07-13 21:39:02 +03:00
getExportedBonusList ( ) . getBonuses ( bl , Selector : : sourceType ( Bonus : : TOWN_STRUCTURE ) ) ;
2013-06-29 16:05:48 +03:00
for ( Bonus * b : bl )
2011-02-21 06:13:00 +02:00
removeBonus ( b ) ;
2011-02-04 16:58:14 +02:00
2012-09-05 15:49:23 +03:00
//tricky! -> checks tavern only if no bratherhood of sword or not a castle
2013-02-11 02:24:57 +03:00
if ( subID ! = ETownType : : CASTLE | | ! addBonusIfBuilt ( BuildingID : : BROTHERHOOD , Bonus : : MORALE , + 2 ) )
addBonusIfBuilt ( BuildingID : : TAVERN , Bonus : : MORALE , + 1 ) ;
2011-02-04 16:58:14 +02:00
2012-09-05 15:49:23 +03:00
if ( subID = = ETownType : : CASTLE ) //castle
2011-02-21 06:13:00 +02:00
{
2013-04-21 15:49:26 +03:00
addBonusIfBuilt ( BuildingID : : LIGHTHOUSE , Bonus : : SEA_MOVEMENT , + 500 , playerProp ) ;
addBonusIfBuilt ( BuildingID : : GRAIL , Bonus : : MORALE , + 2 , playerProp ) ; //colossus
2011-02-21 06:13:00 +02:00
}
2012-09-05 15:49:23 +03:00
else if ( subID = = ETownType : : RAMPART ) //rampart
2011-02-21 06:13:00 +02:00
{
2013-02-11 02:24:57 +03:00
addBonusIfBuilt ( BuildingID : : FOUNTAIN_OF_FORTUNE , Bonus : : LUCK , + 2 ) ; //fountain of fortune
2013-04-21 15:49:26 +03:00
addBonusIfBuilt ( BuildingID : : GRAIL , Bonus : : LUCK , + 2 , playerProp ) ; //guardian spirit
2011-02-21 06:13:00 +02:00
}
2012-09-26 16:13:39 +03:00
else if ( subID = = ETownType : : TOWER ) //tower
2011-02-21 06:13:00 +02:00
{
2013-02-11 02:24:57 +03:00
addBonusIfBuilt ( BuildingID : : GRAIL , Bonus : : PRIMARY_SKILL , + 15 , PrimarySkill : : KNOWLEDGE ) ; //grail
2011-02-21 06:13:00 +02:00
}
2012-09-26 16:13:39 +03:00
else if ( subID = = ETownType : : INFERNO ) //Inferno
2011-02-21 06:13:00 +02:00
{
2013-02-11 02:24:57 +03:00
addBonusIfBuilt ( BuildingID : : STORMCLOUDS , Bonus : : PRIMARY_SKILL , + 2 , PrimarySkill : : SPELL_POWER ) ; //Brimstone Clouds
2011-02-21 06:13:00 +02:00
}
2012-09-05 15:49:23 +03:00
else if ( subID = = ETownType : : NECROPOLIS ) //necropolis
2011-02-21 06:13:00 +02:00
{
2013-02-11 02:24:57 +03:00
addBonusIfBuilt ( BuildingID : : COVER_OF_DARKNESS , Bonus : : DARKNESS , + 20 ) ;
2013-04-21 15:49:26 +03:00
addBonusIfBuilt ( BuildingID : : NECROMANCY_AMPLIFIER , Bonus : : SECONDARY_SKILL_PREMY , + 10 , playerProp , SecondarySkill : : NECROMANCY ) ; //necromancy amplifier
addBonusIfBuilt ( BuildingID : : GRAIL , Bonus : : SECONDARY_SKILL_PREMY , + 20 , playerProp , SecondarySkill : : NECROMANCY ) ; //Soul prison
2011-02-21 06:13:00 +02:00
}
2012-09-05 15:49:23 +03:00
else if ( subID = = ETownType : : DUNGEON ) //Dungeon
2011-02-21 06:13:00 +02:00
{
2013-02-11 02:24:57 +03:00
addBonusIfBuilt ( BuildingID : : GRAIL , Bonus : : PRIMARY_SKILL , + 12 , PrimarySkill : : SPELL_POWER ) ; //grail
2011-02-21 06:13:00 +02:00
}
2012-09-05 15:49:23 +03:00
else if ( subID = = ETownType : : STRONGHOLD ) //Stronghold
2011-02-21 06:13:00 +02:00
{
2013-02-11 02:24:57 +03:00
addBonusIfBuilt ( BuildingID : : GRAIL , Bonus : : PRIMARY_SKILL , + 20 , PrimarySkill : : ATTACK ) ; //grail
2011-02-21 06:13:00 +02:00
}
2012-09-05 15:49:23 +03:00
else if ( subID = = ETownType : : FORTRESS ) //Fortress
2011-02-21 06:13:00 +02:00
{
2013-02-11 02:24:57 +03:00
addBonusIfBuilt ( BuildingID : : GLYPHS_OF_FEAR , Bonus : : PRIMARY_SKILL , + 2 , PrimarySkill : : DEFENSE ) ; //Glyphs of Fear
addBonusIfBuilt ( BuildingID : : BLOOD_OBELISK , Bonus : : PRIMARY_SKILL , + 2 , PrimarySkill : : ATTACK ) ; //Blood Obelisk
addBonusIfBuilt ( BuildingID : : GRAIL , Bonus : : PRIMARY_SKILL , + 10 , PrimarySkill : : ATTACK ) ; //grail
addBonusIfBuilt ( BuildingID : : GRAIL , Bonus : : PRIMARY_SKILL , + 10 , PrimarySkill : : DEFENSE ) ; //grail
2011-02-21 06:13:00 +02:00
}
2012-09-05 15:49:23 +03:00
else if ( subID = = ETownType : : CONFLUX )
2011-02-21 06:13:00 +02:00
{
2011-02-04 16:58:14 +02:00
2011-02-21 06:13:00 +02:00
}
}
2013-02-16 17:03:47 +03:00
bool CGTownInstance : : addBonusIfBuilt ( BuildingID building , Bonus : : BonusType type , int val , int subtype /*= -1*/ )
2011-02-21 06:13:00 +02:00
{
2013-04-21 15:49:26 +03:00
static auto emptyPropagator = TPropagatorPtr ( ) ;
return addBonusIfBuilt ( building , type , val , emptyPropagator , subtype ) ;
2011-02-21 06:13:00 +02:00
}
2013-04-21 15:49:26 +03:00
bool CGTownInstance : : addBonusIfBuilt ( BuildingID building , Bonus : : BonusType type , int val , TPropagatorPtr & prop , int subtype /*= -1*/ )
2011-02-21 06:13:00 +02:00
{
2012-09-05 15:49:23 +03:00
if ( hasBuilt ( building ) )
2011-02-21 06:13:00 +02:00
{
std : : ostringstream descr ;
2012-10-05 16:11:26 +03:00
descr < < town - > buildings [ building ] - > Name ( ) < < " " ;
2011-02-21 06:13:00 +02:00
if ( val > 0 )
descr < < " + " ;
else if ( val < 0 )
descr < < " - " ;
descr < < val ;
Bonus * b = new Bonus ( Bonus : : PERMANENT , type , Bonus : : TOWN_STRUCTURE , val , building , descr . str ( ) , subtype ) ;
if ( prop )
b - > addPropagator ( prop ) ;
addNewBonus ( b ) ;
return true ;
}
return false ;
2011-02-04 16:58:14 +02:00
}
void CGTownInstance : : setVisitingHero ( CGHeroInstance * h )
{
assert ( ! ! visitingHero = = ! h ) ;
if ( h )
{
PlayerState * p = cb - > gameState ( ) - > getPlayer ( h - > tempOwner ) ;
assert ( p ) ;
h - > detachFrom ( p ) ;
h - > attachTo ( & townAndVis ) ;
visitingHero = h ;
h - > visitedTown = this ;
h - > inTownGarrison = false ;
}
else
{
PlayerState * p = cb - > gameState ( ) - > getPlayer ( visitingHero - > tempOwner ) ;
2013-06-26 14:18:27 +03:00
visitingHero - > visitedTown = nullptr ;
2011-02-04 16:58:14 +02:00
visitingHero - > detachFrom ( & townAndVis ) ;
visitingHero - > attachTo ( p ) ;
2013-06-26 14:18:27 +03:00
visitingHero = nullptr ;
2011-02-04 16:58:14 +02:00
}
}
void CGTownInstance : : setGarrisonedHero ( CGHeroInstance * h )
{
assert ( ! ! garrisonHero = = ! h ) ;
if ( h )
{
PlayerState * p = cb - > gameState ( ) - > getPlayer ( h - > tempOwner ) ;
assert ( p ) ;
h - > detachFrom ( p ) ;
h - > attachTo ( this ) ;
garrisonHero = h ;
h - > visitedTown = this ;
h - > inTownGarrison = true ;
}
else
{
PlayerState * p = cb - > gameState ( ) - > getPlayer ( garrisonHero - > tempOwner ) ;
2013-06-26 14:18:27 +03:00
garrisonHero - > visitedTown = nullptr ;
2011-02-04 16:58:14 +02:00
garrisonHero - > inTownGarrison = false ;
garrisonHero - > detachFrom ( this ) ;
garrisonHero - > attachTo ( p ) ;
2013-06-26 14:18:27 +03:00
garrisonHero = nullptr ;
2011-02-04 16:58:14 +02:00
}
2013-04-27 11:11:20 +03:00
updateMoraleBonusFromArmy ( ) ; //avoid giving morale bonus for same army twice
2011-02-04 16:58:14 +02:00
}
2011-02-21 06:13:00 +02:00
bool CGTownInstance : : armedGarrison ( ) const
{
return stacksCount ( ) | | garrisonHero ;
}
2013-07-22 19:23:23 +03:00
int CGTownInstance : : getTownLevel ( ) const
{
// count all buildings that are not upgrades
return boost : : range : : count_if ( builtBuildings , [ & ] ( const BuildingID & build )
{
return town - > buildings [ build ] & & town - > buildings [ build ] - > upgrade = = - 1 ;
} ) ;
}
2011-02-22 11:47:25 +02:00
CBonusSystemNode * CGTownInstance : : whatShouldBeAttached ( )
{
return & townAndVis ;
}
2011-02-25 19:57:30 +02:00
const CArmedInstance * CGTownInstance : : getUpperArmy ( ) const
{
if ( garrisonHero )
return garrisonHero ;
return this ;
}
2013-02-11 22:11:34 +03:00
bool CGTownInstance : : hasBuilt ( BuildingID buildingID , int townID ) const
2012-09-05 15:49:23 +03:00
{
2013-04-21 15:49:26 +03:00
if ( townID = = town - > faction - > index | | townID = = ETownType : : ANY )
2012-09-05 15:49:23 +03:00
return hasBuilt ( buildingID ) ;
return false ;
}
2013-02-11 22:11:34 +03:00
bool CGTownInstance : : hasBuilt ( BuildingID buildingID ) const
2012-01-03 04:55:26 +03:00
{
return vstd : : contains ( builtBuildings , buildingID ) ;
}
2013-02-14 16:19:03 +03:00
void CGTownInstance : : addHeroToStructureVisitors ( const CGHeroInstance * h , si32 structureInstanceID ) const
{
if ( visitingHero = = h )
cb - > setObjProperty ( id , ObjProperty : : STRUCTURE_ADD_VISITING_HERO , structureInstanceID ) ; //add to visitors
else if ( garrisonHero = = h )
cb - > setObjProperty ( id , ObjProperty : : STRUCTURE_ADD_GARRISONED_HERO , structureInstanceID ) ; //then it must be garrisoned hero
else
{
//should never ever happen
2013-04-09 17:31:36 +03:00
logGlobal - > errorStream ( ) < < " Cannot add hero " < < h - > name < < " to visitors of structure # " < < structureInstanceID ;
2013-02-14 16:19:03 +03:00
assert ( 0 ) ;
}
}
2013-04-20 14:34:01 +03:00
void CGTownInstance : : battleFinished ( const CGHeroInstance * hero , const BattleResult & result ) const
{
if ( result . winner = = 0 )
{
removeCapitols ( hero - > getOwner ( ) ) ;
cb - > setOwner ( this , hero - > tempOwner ) ; //give control after checkout is done
FoWChange fw ;
fw . player = hero - > tempOwner ;
fw . mode = 1 ;
getSightTiles ( fw . tiles ) ; //update visibility for castle structures
cb - > sendAndApply ( & fw ) ;
}
}
2012-09-05 15:49:23 +03:00
2012-03-14 16:02:38 +03:00
bool CGVisitableOPH : : wasVisited ( const CGHeroInstance * h ) const
{
return vstd : : contains ( visitors , h - > id ) ;
}
2008-12-27 03:01:59 +02:00
void CGVisitableOPH : : onHeroVisit ( const CGHeroInstance * h ) const
2008-12-22 19:48:41 +02:00
{
2013-02-14 02:55:42 +03:00
if ( ! vstd : : contains ( visitors , h - > id ) )
2008-10-26 22:58:34 +02:00
{
2013-04-22 16:23:53 +03:00
onNAHeroVisit ( h , false ) ;
2009-04-11 04:32:50 +03:00
switch ( ID )
{
2013-01-03 15:19:20 +03:00
case Obj : : TREE_OF_KNOWLEDGE :
case Obj : : ARENA :
case Obj : : LIBRARY_OF_ENLIGHTENMENT :
case Obj : : SCHOOL_OF_MAGIC :
case Obj : : SCHOOL_OF_WAR :
2009-04-11 04:32:50 +03:00
break ;
default :
2013-02-14 02:55:42 +03:00
cb - > setObjProperty ( id , ObjProperty : : VISITORS , h - > id . getNum ( ) ) ; //add to the visitors
2009-04-11 04:32:50 +03:00
break ;
}
2008-10-26 22:58:34 +02:00
}
2008-12-22 19:48:41 +02:00
else
2008-10-26 22:58:34 +02:00
{
2013-04-22 16:23:53 +03:00
onNAHeroVisit ( h , true ) ;
2008-10-26 22:58:34 +02:00
}
2008-12-22 19:48:41 +02:00
}
2008-10-26 22:58:34 +02:00
2008-12-22 19:48:41 +02:00
void CGVisitableOPH : : initObj ( )
{
2012-09-23 21:01:04 +03:00
if ( ID = = Obj : : TREE_OF_KNOWLEDGE )
2013-04-20 14:34:01 +03:00
{
switch ( ran ( ) % 3 )
{
case 1 :
treePrice [ Res : : GOLD ] = 2000 ;
break ;
case 2 :
treePrice [ Res : : GEMS ] = 10 ;
break ;
2013-04-21 15:49:26 +03:00
default :
2013-04-20 14:34:01 +03:00
break ;
}
}
2008-12-22 19:48:41 +02:00
}
2008-10-26 22:58:34 +02:00
2013-04-22 16:23:53 +03:00
void CGVisitableOPH : : treeSelected ( const CGHeroInstance * h , ui32 result ) const
2008-12-22 19:48:41 +02:00
{
2009-04-11 04:32:50 +03:00
if ( result ) //player agreed to give res for exp
2008-10-26 22:58:34 +02:00
{
2013-04-20 14:34:01 +03:00
si64 expToGive = VLC - > heroh - > reqExp ( h - > level + 1 ) - VLC - > heroh - > reqExp ( h - > level ) ; ;
2013-04-22 16:23:53 +03:00
cb - > giveResources ( h - > getOwner ( ) , - treePrice ) ;
cb - > changePrimSkill ( h , PrimarySkill : : EXPERIENCE , expToGive ) ;
cb - > setObjProperty ( id , ObjProperty : : VISITORS , h - > id . getNum ( ) ) ; //add to the visitors
2008-10-26 22:58:34 +02:00
}
2008-12-22 19:48:41 +02:00
}
2013-04-22 16:23:53 +03:00
void CGVisitableOPH : : onNAHeroVisit ( const CGHeroInstance * h , bool alreadyVisited ) const
2008-12-22 19:48:41 +02:00
{
2013-01-12 16:53:02 +03:00
Component : : EComponentType c_id = Component : : PRIM_SKILL ; //most used here
2012-08-31 20:39:11 +03:00
int subid = 0 , ot = 0 , sound = 0 ;
2012-09-23 21:01:04 +03:00
TExpType val = 1 ;
2008-12-22 19:48:41 +02:00
switch ( ID )
2008-11-14 20:18:13 +02:00
{
2012-09-23 21:01:04 +03:00
case Obj : : ARENA :
2009-04-24 00:09:10 +03:00
sound = soundBase : : NOMAD ;
2009-01-11 00:08:18 +02:00
ot = 0 ;
break ;
2012-09-23 21:01:04 +03:00
case Obj : : MERCENARY_CAMP :
2009-04-24 00:09:10 +03:00
sound = soundBase : : NOMAD ;
2013-01-12 16:53:02 +03:00
subid = PrimarySkill : : ATTACK ;
2008-12-22 19:48:41 +02:00
ot = 80 ;
break ;
2012-09-23 21:01:04 +03:00
case Obj : : MARLETTO_TOWER :
2009-04-24 00:09:10 +03:00
sound = soundBase : : NOMAD ;
2013-01-12 16:53:02 +03:00
subid = PrimarySkill : : DEFENSE ;
2008-12-22 19:48:41 +02:00
ot = 39 ;
break ;
2012-09-23 21:01:04 +03:00
case Obj : : STAR_AXIS :
2009-04-24 00:09:10 +03:00
sound = soundBase : : gazebo ;
2013-01-12 16:53:02 +03:00
subid = PrimarySkill : : SPELL_POWER ;
2008-12-22 19:48:41 +02:00
ot = 100 ;
break ;
2012-09-23 21:01:04 +03:00
case Obj : : GARDEN_OF_REVELATION :
2009-04-24 00:09:10 +03:00
sound = soundBase : : GETPROTECTION ;
2013-01-12 16:53:02 +03:00
subid = PrimarySkill : : KNOWLEDGE ;
2008-12-22 19:48:41 +02:00
ot = 59 ;
break ;
2012-09-23 21:01:04 +03:00
case Obj : : LEARNING_STONE :
2009-04-24 00:09:10 +03:00
sound = soundBase : : gazebo ;
2013-01-12 16:53:02 +03:00
c_id = Component : : EXPERIENCE ;
2008-12-22 19:48:41 +02:00
ot = 143 ;
val = 1000 ;
break ;
2012-09-23 21:01:04 +03:00
case Obj : : TREE_OF_KNOWLEDGE :
2009-04-24 00:09:10 +03:00
sound = soundBase : : gazebo ;
2013-01-12 16:53:02 +03:00
c_id = Component : : EXPERIENCE ;
2008-12-22 19:48:41 +02:00
subid = 1 ;
2013-01-12 13:32:03 +03:00
ot = 147 ;
2008-12-22 19:48:41 +02:00
val = 1 ;
break ;
2012-09-23 21:01:04 +03:00
case Obj : : LIBRARY_OF_ENLIGHTENMENT :
2009-04-24 00:09:10 +03:00
sound = soundBase : : gazebo ;
2009-02-01 16:11:41 +02:00
ot = 66 ;
break ;
2012-09-23 21:01:04 +03:00
case Obj : : SCHOOL_OF_MAGIC :
2009-04-24 00:09:10 +03:00
sound = soundBase : : faerie ;
2009-04-11 04:32:50 +03:00
ot = 71 ;
break ;
2012-09-23 21:01:04 +03:00
case Obj : : SCHOOL_OF_WAR :
2013-01-12 16:53:02 +03:00
c_id = Component : : PRIM_SKILL ;
2009-04-24 00:09:10 +03:00
sound = soundBase : : MILITARY ;
2009-04-11 04:32:50 +03:00
ot = 158 ;
break ;
2008-11-14 20:18:13 +02:00
}
2008-12-22 19:48:41 +02:00
if ( ! alreadyVisited )
2008-10-26 22:58:34 +02:00
{
2008-12-22 19:48:41 +02:00
switch ( ID )
2008-10-26 22:58:34 +02:00
{
2012-09-23 21:01:04 +03:00
case Obj : : ARENA :
2009-01-11 00:08:18 +02:00
{
2009-04-11 04:32:50 +03:00
BlockingDialog sd ( false , true ) ;
2009-04-24 00:09:10 +03:00
sd . soundID = sound ;
2013-01-12 13:32:03 +03:00
sd . text . addTxt ( MetaString : : ADVOB_TXT , ot ) ;
2013-01-12 16:53:02 +03:00
sd . components . push_back ( Component ( c_id , PrimarySkill : : ATTACK , 2 , 0 ) ) ;
sd . components . push_back ( Component ( c_id , PrimarySkill : : DEFENSE , 2 , 0 ) ) ;
2013-04-22 16:23:53 +03:00
sd . player = h - > getOwner ( ) ;
2013-04-20 14:34:01 +03:00
cb - > showBlockingDialog ( & sd ) ;
2009-01-11 00:08:18 +02:00
return ;
}
2012-09-23 21:01:04 +03:00
case Obj : : MERCENARY_CAMP :
case Obj : : MARLETTO_TOWER :
case Obj : : STAR_AXIS :
case Obj : : GARDEN_OF_REVELATION :
2008-10-26 22:58:34 +02:00
{
2013-04-22 16:23:53 +03:00
cb - > changePrimSkill ( h , static_cast < PrimarySkill : : PrimarySkill > ( subid ) , val ) ;
2008-12-22 19:48:41 +02:00
InfoWindow iw ;
2009-04-24 00:09:10 +03:00
iw . soundID = sound ;
2013-02-04 22:43:16 +03:00
iw . components . push_back ( Component ( c_id , subid , val , 0 ) ) ;
2013-01-12 13:32:03 +03:00
iw . text . addTxt ( MetaString : : ADVOB_TXT , ot ) ;
2013-04-22 16:23:53 +03:00
iw . player = h - > getOwner ( ) ;
2008-12-22 19:48:41 +02:00
cb - > showInfoDialog ( & iw ) ;
break ;
}
2012-09-23 21:01:04 +03:00
case Obj : : LEARNING_STONE : //give exp
2008-12-22 19:48:41 +02:00
{
2011-02-12 20:48:11 +02:00
val = h - > calculateXp ( val ) ;
2008-12-22 19:48:41 +02:00
InfoWindow iw ;
2009-04-24 00:09:10 +03:00
iw . soundID = sound ;
2013-04-22 16:23:53 +03:00
iw . components . push_back ( Component ( c_id , subid , val , 0 ) ) ;
iw . player = h - > getOwner ( ) ;
2013-01-12 13:32:03 +03:00
iw . text . addTxt ( MetaString : : ADVOB_TXT , ot ) ;
2008-12-22 19:48:41 +02:00
cb - > showInfoDialog ( & iw ) ;
2013-02-09 00:17:39 +03:00
cb - > changePrimSkill ( h , PrimarySkill : : EXPERIENCE , val ) ;
2008-12-22 19:48:41 +02:00
break ;
}
2012-09-23 21:01:04 +03:00
case Obj : : TREE_OF_KNOWLEDGE :
2008-12-22 19:48:41 +02:00
{
2013-04-22 16:23:53 +03:00
val = VLC - > heroh - > reqExp ( h - > level + val ) - VLC - > heroh - > reqExp ( h - > level ) ;
2013-04-20 14:34:01 +03:00
if ( ! treePrice . nonZero ( ) )
2008-10-26 22:58:34 +02:00
{
2013-04-22 16:23:53 +03:00
cb - > setObjProperty ( id , ObjProperty : : VISITORS , h - > id . getNum ( ) ) ; //add to the visitors
2008-12-22 19:48:41 +02:00
InfoWindow iw ;
2009-04-24 00:09:10 +03:00
iw . soundID = sound ;
2013-04-22 16:23:53 +03:00
iw . components . push_back ( Component ( c_id , subid , 1 , 0 ) ) ;
iw . player = h - > getOwner ( ) ;
iw . text . addTxt ( MetaString : : ADVOB_TXT , 148 ) ;
cb - > showInfoDialog ( & iw ) ;
cb - > changePrimSkill ( h , PrimarySkill : : EXPERIENCE , val ) ;
2008-10-26 22:58:34 +02:00
break ;
}
2008-12-22 19:48:41 +02:00
else
{
2013-04-20 14:34:01 +03:00
if ( treePrice [ Res : : GOLD ] > 0 )
2008-12-22 19:48:41 +02:00
ot = 149 ;
else
ot = 151 ;
2013-04-20 14:34:01 +03:00
if ( ! cb - > getPlayer ( h - > tempOwner ) - > resources . canAfford ( treePrice ) ) //not enough resources
2008-12-22 19:48:41 +02:00
{
ot + + ;
2013-01-12 13:32:03 +03:00
showInfoDialog ( h , ot , sound ) ;
2008-12-22 19:48:41 +02:00
return ;
}
2009-10-03 14:16:42 +03:00
BlockingDialog sd ( true , false ) ;
2009-04-24 00:09:10 +03:00
sd . soundID = sound ;
2013-04-22 16:23:53 +03:00
sd . player = h - > getOwner ( ) ;
sd . text . addTxt ( MetaString : : ADVOB_TXT , ot ) ;
sd . addResourceComponents ( treePrice ) ;
cb - > showBlockingDialog ( & sd ) ;
2008-12-22 19:48:41 +02:00
}
break ;
2008-10-26 22:58:34 +02:00
}
2012-09-23 21:01:04 +03:00
case Obj : : LIBRARY_OF_ENLIGHTENMENT :
2009-02-01 16:11:41 +02:00
{
2013-01-12 13:32:03 +03:00
int txt_id = 66 ;
2013-02-04 22:43:16 +03:00
if ( h - > level < 10 - 2 * h - > getSecSkillLevel ( SecondarySkill : : DIPLOMACY ) ) //not enough level
2009-02-01 16:11:41 +02:00
{
2013-01-12 13:32:03 +03:00
txt_id + = 2 ;
2009-02-01 16:11:41 +02:00
}
else
{
2013-04-22 16:23:53 +03:00
cb - > setObjProperty ( id , ObjProperty : : VISITORS , h - > id . getNum ( ) ) ; //add to the visitors
cb - > changePrimSkill ( h , PrimarySkill : : ATTACK , 2 ) ;
cb - > changePrimSkill ( h , PrimarySkill : : DEFENSE , 2 ) ;
cb - > changePrimSkill ( h , PrimarySkill : : KNOWLEDGE , 2 ) ;
cb - > changePrimSkill ( h , PrimarySkill : : SPELL_POWER , 2 ) ;
2009-02-01 16:11:41 +02:00
}
2013-01-12 13:32:03 +03:00
showInfoDialog ( h , txt_id , sound ) ;
2009-02-01 16:11:41 +02:00
break ;
}
2012-09-23 21:01:04 +03:00
case Obj : : SCHOOL_OF_MAGIC :
case Obj : : SCHOOL_OF_WAR :
2009-04-11 04:32:50 +03:00
{
2012-09-23 21:01:04 +03:00
int skill = ( ID = = Obj : : SCHOOL_OF_MAGIC ? 2 : 0 ) ;
2013-04-22 16:23:53 +03:00
if ( cb - > getResource ( h - > getOwner ( ) , Res : : GOLD ) < 1000 ) //not enough resources
2009-04-11 04:32:50 +03:00
{
2013-04-22 16:23:53 +03:00
showInfoDialog ( h - > getOwner ( ) , ot + 2 , sound ) ;
2009-04-11 04:32:50 +03:00
}
else
{
BlockingDialog sd ( true , true ) ;
2009-04-24 00:09:10 +03:00
sd . soundID = sound ;
2013-04-22 16:23:53 +03:00
sd . player = h - > getOwner ( ) ;
2013-01-12 13:32:03 +03:00
sd . text . addTxt ( MetaString : : ADVOB_TXT , ot ) ;
2013-01-12 16:53:02 +03:00
sd . components . push_back ( Component ( c_id , skill , + 1 , 0 ) ) ;
sd . components . push_back ( Component ( c_id , skill + 1 , + 1 , 0 ) ) ;
2013-04-20 14:34:01 +03:00
cb - > showBlockingDialog ( & sd ) ;
2009-04-11 04:32:50 +03:00
}
}
break ;
2008-10-26 22:58:34 +02:00
}
}
2008-12-22 19:48:41 +02:00
else
{
ot + + ;
2013-04-22 16:23:53 +03:00
showInfoDialog ( h - > getOwner ( ) , ot , sound ) ;
2008-12-22 19:48:41 +02:00
}
2008-02-07 20:45:22 +02:00
}
2007-10-27 22:38:48 +03:00
2008-12-22 19:48:41 +02:00
const std : : string & CGVisitableOPH : : getHoverText ( ) const
2007-10-27 22:38:48 +03:00
{
2009-01-11 00:08:18 +02:00
int pom = - 1 ;
2008-12-22 19:48:41 +02:00
switch ( ID )
{
2012-09-23 21:01:04 +03:00
case Obj : : ARENA :
2009-01-11 00:08:18 +02:00
pom = - 1 ;
break ;
2012-09-23 21:01:04 +03:00
case Obj : : MERCENARY_CAMP :
2012-07-19 21:52:44 +03:00
pom = 8 ;
2008-12-22 19:48:41 +02:00
break ;
2012-09-23 21:01:04 +03:00
case Obj : : MARLETTO_TOWER :
2008-12-22 19:48:41 +02:00
pom = 7 ;
break ;
2012-09-23 21:01:04 +03:00
case Obj : : STAR_AXIS :
2012-07-19 21:52:44 +03:00
pom = 11 ;
2008-12-22 19:48:41 +02:00
break ;
2012-09-23 21:01:04 +03:00
case Obj : : GARDEN_OF_REVELATION :
2012-07-19 21:52:44 +03:00
pom = 4 ;
2008-12-22 19:48:41 +02:00
break ;
2012-09-23 21:01:04 +03:00
case Obj : : LEARNING_STONE :
2012-07-19 21:52:44 +03:00
pom = 5 ;
2008-12-22 19:48:41 +02:00
break ;
2012-09-23 21:01:04 +03:00
case Obj : : TREE_OF_KNOWLEDGE :
2008-12-22 19:48:41 +02:00
pom = 18 ;
break ;
2012-09-23 21:01:04 +03:00
case Obj : : LIBRARY_OF_ENLIGHTENMENT :
2009-02-01 16:11:41 +02:00
break ;
2012-09-23 21:01:04 +03:00
case Obj : : SCHOOL_OF_MAGIC :
2009-04-11 04:32:50 +03:00
pom = 9 ;
break ;
2012-09-23 21:01:04 +03:00
case Obj : : SCHOOL_OF_WAR :
2009-04-11 04:32:50 +03:00
pom = 10 ;
break ;
2008-12-22 19:48:41 +02:00
default :
2012-04-22 10:32:45 +03:00
throw std : : runtime_error ( " Wrong CGVisitableOPH object ID! \n " ) ;
2008-12-22 19:48:41 +02:00
}
2009-01-11 00:08:18 +02:00
hoverName = VLC - > generaltexth - > names [ ID ] ;
if ( pom > = 0 )
2010-07-31 03:26:34 +03:00
hoverName + = ( " \n " + VLC - > generaltexth - > xtrainfo [ pom ] ) ;
2013-04-22 16:23:53 +03:00
const CGHeroInstance * h = cb - > getSelectedHero ( cb - > getCurrentPlayer ( ) ) ;
2008-12-22 19:48:41 +02:00
if ( h )
{
2010-07-31 03:26:34 +03:00
hoverName + = " \n \n " ;
2013-04-22 16:23:53 +03:00
bool visited = vstd : : contains ( visitors , h - > id ) ;
hoverName + = visitedTxt ( visited ) ;
2008-12-22 19:48:41 +02:00
}
return hoverName ;
2007-10-27 22:38:48 +03:00
}
2013-04-22 16:23:53 +03:00
void CGVisitableOPH : : arenaSelected ( const CGHeroInstance * h , int primSkill ) const
2009-01-11 00:08:18 +02:00
{
2013-04-22 16:23:53 +03:00
cb - > setObjProperty ( id , ObjProperty : : VISITORS , h - > id . getNum ( ) ) ; //add to the visitors
cb - > changePrimSkill ( h , static_cast < PrimarySkill : : PrimarySkill > ( primSkill - 1 ) , 2 ) ;
2009-01-11 00:08:18 +02:00
}
2009-02-20 14:39:27 +02:00
void CGVisitableOPH : : setPropertyDer ( ui8 what , ui32 val )
{
2010-05-02 21:20:26 +03:00
if ( what = = ObjProperty : : VISITORS )
2013-02-14 02:55:42 +03:00
visitors . insert ( ObjectInstanceID ( val ) ) ;
2009-02-20 14:39:27 +02:00
}
2013-04-22 16:23:53 +03:00
void CGVisitableOPH : : schoolSelected ( const CGHeroInstance * h , ui32 which ) const
2009-04-11 04:32:50 +03:00
{
if ( ! which ) //player refused to pay
return ;
2012-09-23 21:01:04 +03:00
int base = ( ID = = Obj : : SCHOOL_OF_MAGIC ? 2 : 0 ) ;
2013-04-22 16:23:53 +03:00
cb - > setObjProperty ( id , ObjProperty : : VISITORS , h - > id . getNum ( ) ) ; //add to the visitors
cb - > giveResource ( h - > getOwner ( ) , Res : : GOLD , - 1000 ) ; //take 1000 gold
cb - > changePrimSkill ( h , static_cast < PrimarySkill : : PrimarySkill > ( base + which - 1 ) , + 1 ) ; //give appropriate skill
2009-04-11 04:32:50 +03:00
}
2013-04-22 16:23:53 +03:00
void CGVisitableOPH : : blockingDialogAnswered ( const CGHeroInstance * h , ui32 answer ) const
2013-04-20 14:34:01 +03:00
{
switch ( ID )
{
case Obj : : ARENA :
2013-04-22 16:23:53 +03:00
arenaSelected ( h , answer ) ;
2013-04-20 14:34:01 +03:00
break ;
case Obj : : TREE_OF_KNOWLEDGE :
2013-04-22 16:23:53 +03:00
treeSelected ( h , answer ) ;
2013-04-20 14:34:01 +03:00
break ;
case Obj : : SCHOOL_OF_MAGIC :
case Obj : : SCHOOL_OF_WAR :
2013-04-22 16:23:53 +03:00
schoolSelected ( h , answer ) ;
break ;
2013-04-20 14:34:01 +03:00
2013-04-21 15:49:26 +03:00
default :
assert ( 0 ) ;
2013-04-20 14:34:01 +03:00
break ;
}
}
2013-02-11 22:11:34 +03:00
COPWBonus : : COPWBonus ( BuildingID index , CGTownInstance * TOWN )
2009-10-05 19:38:54 +03:00
{
ID = index ;
town = TOWN ;
id = town - > bonusingBuildings . size ( ) ;
}
void COPWBonus : : setProperty ( ui8 what , ui32 val )
{
switch ( what )
{
2013-01-12 13:32:03 +03:00
case ObjProperty : : VISITORS :
2009-10-05 19:38:54 +03:00
visitors . insert ( val ) ;
break ;
2013-02-14 16:19:03 +03:00
case ObjProperty : : STRUCTURE_CLEAR_VISITORS :
2009-10-05 19:38:54 +03:00
visitors . clear ( ) ;
break ;
}
}
void COPWBonus : : onHeroVisit ( const CGHeroInstance * h ) const
{
2013-02-14 02:55:42 +03:00
ObjectInstanceID heroID = h - > id ;
2012-09-05 15:49:23 +03:00
if ( town - > hasBuilt ( ID ) )
2009-10-05 19:38:54 +03:00
{
InfoWindow iw ;
iw . player = h - > tempOwner ;
2009-10-06 10:55:39 +03:00
switch ( town - > subID )
2009-10-05 19:38:54 +03:00
{
2012-09-05 15:49:23 +03:00
case ETownType : : CASTLE : //Stables
2013-01-13 15:40:24 +03:00
if ( ! h - > hasBonusFrom ( Bonus : : OBJECT , Obj : : STABLES ) ) //does not stack with advMap Stables
2009-10-05 19:38:54 +03:00
{
GiveBonus gb ;
2010-05-02 21:20:26 +03:00
gb . bonus = Bonus ( Bonus : : ONE_WEEK , Bonus : : LAND_MOVEMENT , Bonus : : OBJECT , 600 , 94 , VLC - > generaltexth - > arraytxt [ 100 ] ) ;
2013-02-14 02:55:42 +03:00
gb . id = heroID . getNum ( ) ;
2009-10-05 19:38:54 +03:00
cb - > giveHeroBonus ( & gb ) ;
2009-10-06 10:55:39 +03:00
iw . text < < VLC - > generaltexth - > allTexts [ 580 ] ;
cb - > showInfoDialog ( & iw ) ;
}
break ;
2012-09-05 15:49:23 +03:00
case ETownType : : DUNGEON : //Mana Vortex
2011-01-15 19:30:46 +02:00
if ( visitors . empty ( ) & & h - > mana < = h - > manaLimit ( ) * 2 )
2009-10-06 10:55:39 +03:00
{
2012-07-19 21:52:44 +03:00
cb - > setManaPoints ( heroID , 2 * h - > manaLimit ( ) ) ;
2013-02-14 02:55:42 +03:00
//TODO: investigate line below
//cb->setObjProperty (town->id, ObjProperty::VISITED, true);
2009-10-06 10:55:39 +03:00
iw . text < < VLC - > generaltexth - > allTexts [ 579 ] ;
2009-10-05 19:38:54 +03:00
cb - > showInfoDialog ( & iw ) ;
2013-02-14 16:19:03 +03:00
town - > addHeroToStructureVisitors ( h , id ) ;
2009-10-05 19:38:54 +03:00
}
break ;
}
}
}
2013-02-11 22:11:34 +03:00
CTownBonus : : CTownBonus ( BuildingID index , CGTownInstance * TOWN )
2009-08-23 18:02:21 +03:00
{
ID = index ;
town = TOWN ;
2009-09-21 12:00:33 +03:00
id = town - > bonusingBuildings . size ( ) ;
}
void CTownBonus : : setProperty ( ui8 what , ui32 val )
{
2013-02-14 16:19:03 +03:00
if ( what = = ObjProperty : : VISITORS )
2013-02-14 02:55:42 +03:00
visitors . insert ( ObjectInstanceID ( val ) ) ;
2009-08-23 18:02:21 +03:00
}
void CTownBonus : : onHeroVisit ( const CGHeroInstance * h ) const
{
2013-02-14 02:55:42 +03:00
ObjectInstanceID heroID = h - > id ;
2012-09-05 15:49:23 +03:00
if ( town - > hasBuilt ( ID ) & & visitors . find ( heroID ) = = visitors . end ( ) )
2009-08-23 18:02:21 +03:00
{
InfoWindow iw ;
2013-02-04 22:43:16 +03:00
PrimarySkill : : PrimarySkill what = PrimarySkill : : ATTACK ;
int val = 0 , mid = 0 ;
2009-08-23 18:02:21 +03:00
switch ( ID )
{
2013-02-11 02:24:57 +03:00
case BuildingID : : SPECIAL_4 :
2009-09-21 12:00:33 +03:00
switch ( town - > subID )
2009-08-23 18:02:21 +03:00
{
2012-09-05 15:49:23 +03:00
case ETownType : : TOWER : //wall
2013-02-04 22:43:16 +03:00
what = PrimarySkill : : KNOWLEDGE ;
2009-10-05 14:28:49 +03:00
val = 1 ;
2009-10-06 10:55:39 +03:00
mid = 581 ;
2009-08-23 18:02:21 +03:00
iw . components . push_back ( Component ( Component : : PRIM_SKILL , 3 , 1 , 0 ) ) ;
break ;
2012-09-05 15:49:23 +03:00
case ETownType : : INFERNO : //order of fire
2013-02-04 22:43:16 +03:00
what = PrimarySkill : : SPELL_POWER ;
2009-10-05 14:28:49 +03:00
val = 1 ;
2009-10-06 10:55:39 +03:00
mid = 582 ;
2009-08-23 18:02:21 +03:00
iw . components . push_back ( Component ( Component : : PRIM_SKILL , 2 , 1 , 0 ) ) ;
break ;
2013-04-20 14:34:01 +03:00
case ETownType : : STRONGHOLD : //hall of Valhalla
2013-02-04 22:43:16 +03:00
what = PrimarySkill : : ATTACK ;
2009-10-05 14:28:49 +03:00
val = 1 ;
2009-10-06 10:55:39 +03:00
mid = 584 ;
2009-08-23 18:02:21 +03:00
iw . components . push_back ( Component ( Component : : PRIM_SKILL , 0 , 1 , 0 ) ) ;
break ;
2012-09-05 15:49:23 +03:00
case ETownType : : DUNGEON : //academy of battle scholars
2013-02-04 22:43:16 +03:00
what = PrimarySkill : : EXPERIENCE ;
2013-01-12 13:32:03 +03:00
val = h - > calculateXp ( 1000 ) ;
2009-10-06 10:55:39 +03:00
mid = 583 ;
2010-07-26 01:47:59 +03:00
iw . components . push_back ( Component ( Component : : EXPERIENCE , 0 , val , 0 ) ) ;
2009-08-23 18:02:21 +03:00
break ;
}
break ;
2013-02-11 02:24:57 +03:00
case BuildingID : : SPECIAL_1 :
2009-09-21 12:00:33 +03:00
switch ( town - > subID )
2009-08-23 18:02:21 +03:00
{
2012-09-05 15:49:23 +03:00
case ETownType : : FORTRESS : //cage of warlords
2013-02-04 22:43:16 +03:00
what = PrimarySkill : : DEFENSE ;
2009-10-05 14:28:49 +03:00
val = 1 ;
2009-10-06 10:55:39 +03:00
mid = 585 ;
2009-08-23 18:02:21 +03:00
iw . components . push_back ( Component ( Component : : PRIM_SKILL , 1 , 1 , 0 ) ) ;
break ;
}
break ;
}
2012-07-06 23:19:54 +03:00
assert ( mid ) ;
2009-08-23 18:02:21 +03:00
iw . player = cb - > getOwner ( heroID ) ;
2009-10-06 10:55:39 +03:00
iw . text < < VLC - > generaltexth - > allTexts [ mid ] ;
2009-08-23 18:02:21 +03:00
cb - > showInfoDialog ( & iw ) ;
2013-02-09 00:17:39 +03:00
cb - > changePrimSkill ( cb - > getHero ( heroID ) , what , val ) ;
2013-02-14 16:19:03 +03:00
town - > addHeroToStructureVisitors ( h , id ) ;
2009-08-23 18:02:21 +03:00
}
}
2010-06-28 16:33:05 +03:00
const std : : string & CGCreature : : getHoverText ( ) const
2009-08-11 10:50:29 +03:00
{
2013-04-20 14:34:01 +03:00
if ( stacks . empty ( ) )
{
2013-04-21 15:49:26 +03:00
static const std : : string errorValue ( " !!!INVALID_STACK!!! " ) ;
2013-04-20 14:34:01 +03:00
//should not happen...
logGlobal - > errorStream ( ) < < " Invalid stack at tile " < < pos < < " : subID= " < < subID < < " ; id= " < < id ;
2013-04-21 15:49:26 +03:00
return errorValue ; // references to temporary are illegal - use pre-constructed string
2013-04-20 14:34:01 +03:00
}
2010-06-28 16:33:05 +03:00
MetaString ms ;
2011-04-10 11:33:53 +03:00
int pom = stacks . begin ( ) - > second - > getQuantityID ( ) ;
2012-08-08 11:27:52 +03:00
pom = 172 + 3 * pom ;
2013-01-12 13:32:03 +03:00
ms . addTxt ( MetaString : : ARRAY_TXT , pom ) ;
ms < < " " ;
ms . addTxt ( MetaString : : CRE_PL_NAMES , subID ) ;
2010-06-28 16:33:05 +03:00
ms . toString ( hoverName ) ;
2010-07-07 05:29:07 +03:00
if ( const CGHeroInstance * selHero = cb - > getSelectedHero ( cb - > getCurrentPlayer ( ) ) )
{
2011-02-07 16:39:17 +02:00
std : : vector < std : : string > * texts = & VLC - > generaltexth - > threat ;
hoverName + = " \n \n " ;
hoverName + = ( * texts ) [ 0 ] ;
int choice ;
2011-06-21 12:31:08 +03:00
double ratio = ( ( double ) getArmyStrength ( ) / selHero - > getTotalStrength ( ) ) ;
2011-02-07 16:39:17 +02:00
if ( ratio < 0.1 ) choice = 1 ;
else if ( ratio < 0.25 ) choice = 2 ;
else if ( ratio < 0.6 ) choice = 3 ;
else if ( ratio < 0.9 ) choice = 4 ;
else if ( ratio < 1.1 ) choice = 5 ;
else if ( ratio < 1.3 ) choice = 6 ;
else if ( ratio < 1.8 ) choice = 7 ;
else if ( ratio < 2.5 ) choice = 8 ;
else if ( ratio < 4 ) choice = 9 ;
else if ( ratio < 8 ) choice = 10 ;
else if ( ratio < 20 ) choice = 11 ;
else choice = 12 ;
hoverName + = ( * texts ) [ choice ] ;
2010-07-07 05:29:07 +03:00
}
2009-08-11 10:50:29 +03:00
return hoverName ;
2010-06-28 16:33:05 +03:00
}
2008-12-27 03:01:59 +02:00
void CGCreature : : onHeroVisit ( const CGHeroInstance * h ) const
2008-11-28 03:36:34 +02:00
{
2009-04-12 04:48:50 +03:00
int action = takenAction ( h ) ;
switch ( action ) //decide what we do...
{
2013-04-20 14:34:01 +03:00
case FIGHT :
2009-04-12 04:48:50 +03:00
fight ( h ) ;
break ;
2013-04-20 14:34:01 +03:00
case FLEE : //flee
2009-04-12 04:48:50 +03:00
{
flee ( h ) ;
break ;
}
2013-04-20 14:34:01 +03:00
case JOIN_FOR_FREE : //join for free
2009-04-12 04:48:50 +03:00
{
BlockingDialog ynd ( true , false ) ;
ynd . player = h - > tempOwner ;
2013-01-12 13:32:03 +03:00
ynd . text . addTxt ( MetaString : : ADVOB_TXT , 86 ) ;
2009-07-09 22:15:22 +03:00
ynd . text . addReplacement ( MetaString : : CRE_PL_NAMES , subID ) ;
2013-04-20 14:34:01 +03:00
cb - > showBlockingDialog ( & ynd ) ;
2009-04-12 04:48:50 +03:00
break ;
}
default : //join for gold
{
assert ( action > 0 ) ;
//ask if player agrees to pay gold
BlockingDialog ynd ( true , false ) ;
ynd . player = h - > tempOwner ;
std : : string tmp = VLC - > generaltexth - > advobtxt [ 90 ] ;
2013-02-16 17:03:47 +03:00
boost : : algorithm : : replace_first ( tmp , " %d " , boost : : lexical_cast < std : : string > ( getStackCount ( SlotID ( 0 ) ) ) ) ;
2009-04-12 04:48:50 +03:00
boost : : algorithm : : replace_first ( tmp , " %d " , boost : : lexical_cast < std : : string > ( action ) ) ;
2010-05-02 21:20:26 +03:00
boost : : algorithm : : replace_first ( tmp , " %s " , VLC - > creh - > creatures [ subID ] - > namePl ) ;
2009-04-12 04:48:50 +03:00
ynd . text < < tmp ;
2013-04-20 14:34:01 +03:00
cb - > showBlockingDialog ( & ynd ) ;
2009-04-12 04:48:50 +03:00
break ;
}
}
2008-11-28 03:36:34 +02:00
}
2008-09-12 11:51:46 +03:00
2008-12-22 19:48:41 +02:00
void CGCreature : : initObj ( )
2007-10-27 22:38:48 +03:00
{
2009-04-08 22:55:50 +03:00
blockVisit = true ;
2009-04-12 04:48:50 +03:00
switch ( character )
{
case 0 :
2012-01-19 17:33:22 +03:00
character = - 4 ;
2009-04-12 04:48:50 +03:00
break ;
case 1 :
character = 1 + ran ( ) % 7 ;
break ;
case 2 :
character = 1 + ran ( ) % 10 ;
break ;
case 3 :
character = 4 + ran ( ) % 7 ;
break ;
case 4 :
character = 10 ;
break ;
}
2013-02-16 17:03:47 +03:00
stacks [ SlotID ( 0 ) ] - > setType ( CreatureID ( subID ) ) ;
TQuantity & amount = stacks [ SlotID ( 0 ) ] - > count ;
2010-05-02 21:20:26 +03:00
CCreature & c = * VLC - > creh - > creatures [ subID ] ;
2008-12-22 19:48:41 +02:00
if ( ! amount )
2010-08-30 02:12:34 +03:00
{
2008-12-22 19:48:41 +02:00
if ( c . ammMax = = c . ammMin )
amount = c . ammMax ;
else
amount = c . ammMin + ( ran ( ) % ( c . ammMax - c . ammMin ) ) ;
2013-02-19 01:37:22 +03:00
if ( ! amount ) //armies with 0 creatures are illegal
{
2013-04-09 17:31:36 +03:00
logGlobal - > warnStream ( ) < < " Problem: stack " < < nodeName ( ) < < " cannot have 0 creatures. Check properties of " < < c . nodeName ( ) ;
2013-02-19 01:37:22 +03:00
amount = 1 ;
}
2010-08-30 02:12:34 +03:00
}
2013-07-22 12:48:25 +03:00
formation . randomFormation = rand ( ) ;
2010-07-07 15:51:28 +03:00
2013-02-16 17:03:47 +03:00
temppower = stacks [ SlotID ( 0 ) ] - > count * 1000 ;
2013-04-20 14:34:01 +03:00
refusedJoining = false ;
2010-06-26 15:57:16 +03:00
}
2013-04-20 14:34:01 +03:00
2010-06-26 15:57:16 +03:00
void CGCreature : : newTurn ( ) const
{ //Works only for stacks of single type of size up to 2 millions
2013-02-02 11:29:57 +03:00
if ( stacks . begin ( ) - > second - > count < VLC - > modh - > settings . CREEP_SIZE & & cb - > getDate ( Date : : DAY_OF_WEEK ) = = 1 & & cb - > getDate ( Date : : DAY ) > 1 )
2010-06-26 15:57:16 +03:00
{
2012-08-11 12:06:23 +03:00
ui32 power = temppower * ( 100 + VLC - > modh - > settings . WEEKLY_GROWTH ) / 100 ;
cb - > setObjProperty ( id , ObjProperty : : MONSTER_COUNT , std : : min ( power / 1000 , ( ui32 ) VLC - > modh - > settings . CREEP_SIZE ) ) ; //set new amount
2011-05-28 04:02:28 +03:00
cb - > setObjProperty ( id , ObjProperty : : MONSTER_POWER , power ) ; //increase temppower
2010-06-26 15:57:16 +03:00
}
2012-08-24 12:37:52 +03:00
if ( VLC - > modh - > modules . STACK_EXP )
2012-08-11 12:06:23 +03:00
cb - > setObjProperty ( id , ObjProperty : : MONSTER_EXP , VLC - > modh - > settings . NEUTRAL_STACK_EXP ) ; //for testing purpose
2010-06-26 15:57:16 +03:00
}
void CGCreature : : setPropertyDer ( ui8 what , ui32 val )
{
switch ( what )
{
2011-05-28 04:02:28 +03:00
case ObjProperty : : MONSTER_COUNT :
2013-02-16 17:03:47 +03:00
stacks [ SlotID ( 0 ) ] - > count = val ;
2010-06-26 15:57:16 +03:00
break ;
2011-05-28 04:02:28 +03:00
case ObjProperty : : MONSTER_POWER :
2010-06-26 15:57:16 +03:00
temppower = val ;
break ;
2011-05-28 04:02:28 +03:00
case ObjProperty : : MONSTER_EXP :
2011-02-13 15:11:09 +02:00
giveStackExp ( val ) ;
break ;
2011-09-06 09:00:32 +03:00
case ObjProperty : : MONSTER_RESTORE_TYPE :
2013-07-22 12:48:25 +03:00
formation . basicType = val ;
2011-04-14 10:58:19 +03:00
break ;
2013-04-20 14:34:01 +03:00
case ObjProperty : : MONSTER_REFUSED_JOIN :
refusedJoining = val ;
break ;
2010-06-26 15:57:16 +03:00
}
2008-12-27 03:01:59 +02:00
}
2009-04-12 04:48:50 +03:00
int CGCreature : : takenAction ( const CGHeroInstance * h , bool allowJoin ) const
{
2012-01-19 17:33:22 +03:00
//calculate relative strength of hero and creatures armies
double relStrength = double ( h - > getTotalStrength ( ) ) / getArmyStrength ( ) ;
2009-04-12 04:48:50 +03:00
2012-01-19 17:33:22 +03:00
int powerFactor ;
if ( relStrength > = 7 )
powerFactor = 11 ;
2009-04-12 04:48:50 +03:00
2012-01-19 17:33:22 +03:00
else if ( relStrength > = 1 )
powerFactor = ( int ) ( 2 * ( relStrength - 1 ) ) ;
2009-04-12 04:48:50 +03:00
2012-01-19 17:33:22 +03:00
else if ( relStrength > = 0.5 )
powerFactor = - 1 ;
2009-04-12 04:48:50 +03:00
2012-01-19 17:33:22 +03:00
else if ( relStrength > = 0.333 )
powerFactor = - 2 ;
else
powerFactor = - 3 ;
2010-04-02 05:07:40 +03:00
2013-02-14 02:55:42 +03:00
std : : set < CreatureID > myKindCres ; //what creatures are the same kind as we
const CCreature * myCreature = VLC - > creh - > creatures [ subID ] ;
myKindCres . insert ( myCreature - > idNumber ) ; //we
myKindCres . insert ( myCreature - > upgrades . begin ( ) , myCreature - > upgrades . end ( ) ) ; //our upgrades
2012-07-19 21:52:44 +03:00
2013-06-29 16:05:48 +03:00
for ( ConstTransitivePtr < CCreature > & crea : VLC - > creh - > creatures )
2012-01-19 17:33:22 +03:00
{
2013-02-14 02:55:42 +03:00
if ( vstd : : contains ( crea - > upgrades , myCreature - > idNumber ) ) //it's our base creatures
2012-01-19 17:33:22 +03:00
myKindCres . insert ( crea - > idNumber ) ;
}
2009-04-12 04:48:50 +03:00
2012-01-19 17:33:22 +03:00
int count = 0 , //how many creatures of similar kind has hero
totalCount = 0 ;
2009-04-12 04:48:50 +03:00
2013-06-29 16:05:48 +03:00
for ( auto & elem : h - > Slots ( ) )
2012-01-19 17:33:22 +03:00
{
2013-06-29 16:05:48 +03:00
if ( vstd : : contains ( myKindCres , elem . second - > type - > idNumber ) )
count + = elem . second - > count ;
totalCount + = elem . second - > count ;
2009-04-12 04:48:50 +03:00
}
2012-01-19 17:33:22 +03:00
int sympathy = 0 ; // 0 if hero have no similar creatures
if ( count )
sympathy + + ; // 1 - if hero have at least 1 similar creature
if ( count * 2 > totalCount )
sympathy + + ; // 2 - hero have similar creatures more that 50%
2009-04-12 04:48:50 +03:00
2013-02-04 22:43:16 +03:00
int charisma = powerFactor + h - > getSecSkillLevel ( SecondarySkill : : DIPLOMACY ) + sympathy ;
2012-01-19 17:33:22 +03:00
if ( charisma < character ) //creatures will fight
return - 2 ;
if ( allowJoin )
{
2013-02-04 22:43:16 +03:00
if ( h - > getSecSkillLevel ( SecondarySkill : : DIPLOMACY ) + sympathy + 1 > = character )
2012-01-19 17:33:22 +03:00
return 0 ; //join for free
2013-02-04 22:43:16 +03:00
else if ( h - > getSecSkillLevel ( SecondarySkill : : DIPLOMACY ) * 2 + sympathy + 1 > = character )
2013-02-16 17:03:47 +03:00
return VLC - > creh - > creatures [ subID ] - > cost [ 6 ] * getStackCount ( SlotID ( 0 ) ) ; //join for gold
2012-01-19 17:33:22 +03:00
}
//we are still here - creatures have not joined hero, flee or fight
if ( charisma > character )
2009-04-16 03:28:54 +03:00
return - 1 ; //flee
2009-04-12 04:48:50 +03:00
else
2009-04-16 03:28:54 +03:00
return - 2 ; //fight
2009-04-12 04:48:50 +03:00
}
void CGCreature : : fleeDecision ( const CGHeroInstance * h , ui32 pursue ) const
{
2013-04-20 14:34:01 +03:00
if ( refusedJoining )
cb - > setObjProperty ( id , ObjProperty : : MONSTER_REFUSED_JOIN , false ) ;
2009-04-12 04:48:50 +03:00
if ( pursue )
{
fight ( h ) ;
}
else
{
2013-02-09 00:17:39 +03:00
cb - > removeObject ( this ) ;
2009-04-12 04:48:50 +03:00
}
}
void CGCreature : : joinDecision ( const CGHeroInstance * h , int cost , ui32 accept ) const
{
if ( ! accept )
{
if ( takenAction ( h , false ) = = - 1 ) //they flee
{
2013-04-20 14:34:01 +03:00
cb - > setObjProperty ( id , ObjProperty : : MONSTER_REFUSED_JOIN , true ) ;
2009-04-12 04:48:50 +03:00
flee ( h ) ;
}
else //they fight
{
2013-01-12 13:32:03 +03:00
showInfoDialog ( h , 87 , 0 ) ; //Insulted by your refusal of their offer, the monsters attack!
2009-04-12 04:48:50 +03:00
fight ( h ) ;
}
}
else //accepted
{
2013-02-09 15:56:35 +03:00
if ( cb - > getResource ( h - > tempOwner , Res : : GOLD ) < cost ) //player don't have enough gold!
2009-04-12 04:48:50 +03:00
{
InfoWindow iw ;
iw . player = h - > tempOwner ;
iw . text < < std : : pair < ui8 , ui32 > ( 1 , 29 ) ; //You don't have enough gold
cb - > showInfoDialog ( & iw ) ;
//act as if player refused
2009-08-04 02:53:18 +03:00
joinDecision ( h , cost , false ) ;
2009-04-12 04:48:50 +03:00
return ;
}
//take gold
if ( cost )
2013-02-04 22:43:16 +03:00
cb - > giveResource ( h - > tempOwner , Res : : GOLD , - cost ) ;
2009-04-12 04:48:50 +03:00
2011-06-23 13:12:35 +03:00
cb - > tryJoiningArmy ( this , h , true , true ) ;
2009-04-12 04:48:50 +03:00
}
}
void CGCreature : : fight ( const CGHeroInstance * h ) const
{
2011-04-10 11:33:53 +03:00
//split stacks
2011-11-01 15:58:01 +03:00
//TODO: multiple creature types in a stack?
2011-04-10 11:33:53 +03:00
int basicType = stacks . begin ( ) - > second - > type - > idNumber ;
2011-09-06 09:00:32 +03:00
cb - > setObjProperty ( id , ObjProperty : : MONSTER_RESTORE_TYPE , basicType ) ; //store info about creature stack
2011-04-10 11:33:53 +03:00
2011-12-14 00:23:17 +03:00
double relativePower = static_cast < double > ( h - > getTotalStrength ( ) ) / getArmyStrength ( ) ;
2011-04-10 11:33:53 +03:00
int stacksCount ;
//TODO: number depends on tile type
if ( relativePower < 0.5 )
{
stacksCount = 7 ;
}
else if ( relativePower < 0.67 )
{
stacksCount = 7 ;
}
else if ( relativePower < 1 )
{
stacksCount = 6 ;
}
else if ( relativePower < 1.5 )
{
stacksCount = 5 ;
}
else if ( relativePower < 2 )
{
stacksCount = 4 ;
}
else
{
stacksCount = 3 ;
}
int stackSize ;
2013-02-16 17:03:47 +03:00
SlotID sourceSlot = stacks . begin ( ) - > first ;
SlotID destSlot ;
2011-04-10 11:33:53 +03:00
for ( int stacksLeft = stacksCount ; stacksLeft > 1 ; - - stacksLeft )
{
stackSize = stacks . begin ( ) - > second - > count / stacksLeft ;
if ( stackSize )
{
2013-02-16 17:03:47 +03:00
if ( ( destSlot = getFreeSlot ( ) ) . validSlot ( ) )
2011-04-10 11:33:53 +03:00
cb - > moveStack ( StackLocation ( this , sourceSlot ) , StackLocation ( this , destSlot ) , stackSize ) ;
else
{
2013-04-09 17:31:36 +03:00
logGlobal - > warnStream ( ) < < " Warning! Not enough empty slots to split stack! " ;
2011-04-10 11:33:53 +03:00
break ;
}
}
else break ;
}
if ( stacksCount > 1 )
{
2013-07-22 12:48:25 +03:00
if ( formation . randomFormation % 100 < 50 ) //upgrade
2011-04-10 11:33:53 +03:00
{
2013-02-16 17:03:47 +03:00
SlotID slotId = SlotID ( stacks . size ( ) / 2 ) ;
2011-04-10 11:33:53 +03:00
if ( ui32 upgradesSize = getStack ( slotId ) . type - > upgrades . size ( ) )
{
2013-02-07 20:34:50 +03:00
auto it = getStack ( slotId ) . type - > upgrades . cbegin ( ) ; //pick random in case there are more
2011-04-10 11:33:53 +03:00
std : : advance ( it , rand ( ) % upgradesSize ) ;
cb - > changeStackType ( StackLocation ( this , slotId ) , VLC - > creh - > creatures [ * it ] ) ;
}
}
}
2013-04-20 14:34:01 +03:00
cb - > startBattleI ( h , this ) ;
2011-04-10 11:33:53 +03:00
2009-04-12 04:48:50 +03:00
}
void CGCreature : : flee ( const CGHeroInstance * h ) const
{
BlockingDialog ynd ( true , false ) ;
ynd . player = h - > tempOwner ;
2013-01-12 13:32:03 +03:00
ynd . text . addTxt ( MetaString : : ADVOB_TXT , 91 ) ;
2009-07-09 22:15:22 +03:00
ynd . text . addReplacement ( MetaString : : CRE_PL_NAMES , subID ) ;
2013-04-20 14:34:01 +03:00
cb - > showBlockingDialog ( & ynd ) ;
}
void CGCreature : : battleFinished ( const CGHeroInstance * hero , const BattleResult & result ) const
{
if ( result . winner = = 0 )
{
cb - > removeObject ( this ) ;
}
else
{
//int killedAmount=0;
//for(std::set<std::pair<ui32,si32> >::iterator i=result->casualties[1].begin(); i!=result->casualties[1].end(); i++)
// if(i->first == subID)
// killedAmount += i->second;
//cb->setAmount(id, slots.find(0)->second.second - killedAmount);
/*
MetaString ms ;
int pom = slots . find ( 0 ) - > second . getQuantityID ( ) ;
pom = 174 + 3 * pom + 1 ;
ms < < std : : pair < ui8 , ui32 > ( 6 , pom ) < < " " < < std : : pair < ui8 , ui32 > ( 7 , subID ) ;
cb - > setHoverName ( id , & ms ) ;
cb - > setObjProperty ( id , 11 , slots . begin ( ) - > second . count * 1000 ) ;
*/
//merge stacks into one
TSlots : : const_iterator i ;
2013-07-22 12:48:25 +03:00
CCreature * cre = VLC - > creh - > creatures [ formation . basicType ] ;
2013-04-20 14:34:01 +03:00
for ( i = stacks . begin ( ) ; i ! = stacks . end ( ) ; i + + )
{
if ( cre - > isMyUpgrade ( i - > second - > type ) )
{
cb - > changeStackType ( StackLocation ( this , i - > first ) , cre ) ; //un-upgrade creatures
}
}
//first stack has to be at slot 0 -> if original one got killed, move there first remaining stack
if ( ! hasStackAtSlot ( SlotID ( 0 ) ) )
cb - > moveStack ( StackLocation ( this , stacks . begin ( ) - > first ) , StackLocation ( this , SlotID ( 0 ) ) , stacks . begin ( ) - > second - > count ) ;
while ( stacks . size ( ) > 1 ) //hopefully that's enough
{
// TODO it's either overcomplicated (if we assume there'll be only one stack) or buggy (if we allow multiple stacks... but that'll also cause troubles elsewhere)
i = stacks . end ( ) ;
i - - ;
SlotID slot = getSlotFor ( i - > second - > type ) ;
if ( slot = = i - > first ) //no reason to move stack to its own slot
break ;
else
cb - > moveStack ( StackLocation ( this , i - > first ) , StackLocation ( this , slot ) , i - > second - > count ) ;
}
cb - > setObjProperty ( id , ObjProperty : : MONSTER_POWER , stacks . begin ( ) - > second - > count * 1000 ) ; //remember casualties
}
}
void CGCreature : : blockingDialogAnswered ( const CGHeroInstance * hero , ui32 answer ) const
{
auto action = takenAction ( hero ) ;
if ( ! refusedJoining & & action > = JOIN_FOR_FREE ) //higher means price
joinDecision ( hero , action , answer ) ;
else if ( action ! = FIGHT )
fleeDecision ( hero , answer ) ;
else
assert ( 0 ) ;
2009-04-12 04:48:50 +03:00
}
2008-12-27 03:01:59 +02:00
void CGMine : : onHeroVisit ( const CGHeroInstance * h ) const
{
2010-08-13 13:46:08 +03:00
int relations = cb - > gameState ( ) - > getPlayerRelations ( h - > tempOwner , tempOwner ) ;
2012-07-19 21:52:44 +03:00
2010-08-06 16:14:10 +03:00
if ( relations = = 2 ) //we're visiting our mine
2009-04-12 03:58:41 +03:00
{
2013-05-14 16:42:52 +03:00
cb - > showGarrisonDialog ( id , h - > id , true ) ;
2012-07-19 21:52:44 +03:00
return ;
2009-04-12 03:58:41 +03:00
}
2010-08-06 16:14:10 +03:00
else if ( relations = = 1 ) //ally
return ;
2008-12-27 03:01:59 +02:00
2010-08-06 16:14:10 +03:00
if ( stacksCount ( ) ) //Mine is guarded
2010-07-31 03:26:34 +03:00
{
BlockingDialog ynd ( true , false ) ;
ynd . player = h - > tempOwner ;
2013-01-12 13:32:03 +03:00
ynd . text . addTxt ( MetaString : : ADVOB_TXT , subID = = 7 ? 84 : 187 ) ;
2013-04-20 14:34:01 +03:00
cb - > showBlockingDialog ( & ynd ) ;
2010-07-31 03:26:34 +03:00
return ;
}
2008-12-27 03:01:59 +02:00
2010-07-31 03:26:34 +03:00
flagMine ( h - > tempOwner ) ;
2008-12-27 03:01:59 +02:00
}
void CGMine : : newTurn ( ) const
{
2009-05-25 02:21:55 +03:00
if ( cb - > getDate ( ) = = 1 )
return ;
2013-03-03 20:06:03 +03:00
if ( tempOwner = = PlayerColor : : NEUTRAL )
2008-12-27 03:01:59 +02:00
return ;
2010-07-31 04:38:12 +03:00
cb - > giveResource ( tempOwner , producedResource , producedQuantity ) ;
2008-12-27 03:01:59 +02:00
}
void CGMine : : initObj ( )
{
2010-07-31 03:26:34 +03:00
if ( subID > = 7 ) //Abandoned Mine
{
//set guardians
int howManyTroglodytes = 100 + ran ( ) % 100 ;
2013-06-29 16:05:48 +03:00
auto troglodytes = new CStackInstance ( CreatureID : : TROGLODYTES , howManyTroglodytes ) ;
2013-02-16 17:03:47 +03:00
putStack ( SlotID ( 0 ) , troglodytes ) ;
2010-07-31 03:26:34 +03:00
//after map reading tempOwner placeholds bitmask for allowed resources
2013-02-04 22:43:16 +03:00
std : : vector < Res : : ERes > possibleResources ;
2013-03-03 20:06:03 +03:00
for ( int i = 0 ; i < PlayerColor : : PLAYER_LIMIT_I ; i + + )
if ( tempOwner . getNum ( ) & 1 < < i ) //NOTE: reuse of tempOwner
2013-02-04 22:43:16 +03:00
possibleResources . push_back ( static_cast < Res : : ERes > ( i ) ) ;
2010-07-31 03:26:34 +03:00
assert ( possibleResources . size ( ) ) ;
producedResource = possibleResources [ ran ( ) % possibleResources . size ( ) ] ;
2013-03-03 20:06:03 +03:00
tempOwner = PlayerColor : : NEUTRAL ;
2010-11-22 02:34:46 +02:00
hoverName = VLC - > generaltexth - > mines [ 7 ] . first + " \n " + VLC - > generaltexth - > allTexts [ 202 ] + " " + troglodytes - > getQuantityTXT ( false ) + " " + troglodytes - > type - > namePl ;
2010-07-31 03:26:34 +03:00
}
2008-12-27 03:01:59 +02:00
else
2010-07-31 03:26:34 +03:00
{
2013-02-04 22:43:16 +03:00
producedResource = static_cast < Res : : ERes > ( subID ) ;
2010-07-31 03:26:34 +03:00
MetaString ms ;
ms < < std : : pair < ui8 , ui32 > ( 9 , producedResource ) ;
2013-03-03 20:06:03 +03:00
if ( tempOwner > = PlayerColor : : PLAYER_LIMIT )
tempOwner = PlayerColor : : NEUTRAL ;
2010-07-31 03:26:34 +03:00
else
2013-03-03 20:06:03 +03:00
ms < < " ( " < < std : : pair < ui8 , ui32 > ( 6 , 23 + tempOwner . getNum ( ) ) < < " ) " ;
2010-07-31 03:26:34 +03:00
ms . toString ( hoverName ) ;
}
producedQuantity = defaultResProduction ( ) ;
}
2013-03-03 20:06:03 +03:00
void CGMine : : flagMine ( PlayerColor player ) const
2010-07-31 03:26:34 +03:00
{
assert ( tempOwner ! = player ) ;
2013-02-09 00:17:39 +03:00
cb - > setOwner ( this , player ) ; //not ours? flag it!
2010-07-31 03:26:34 +03:00
MetaString ms ;
2013-03-03 20:06:03 +03:00
ms < < std : : pair < ui8 , ui32 > ( 9 , subID ) < < " \n ( " < < std : : pair < ui8 , ui32 > ( 6 , 23 + player . getNum ( ) ) < < " ) " ;
2010-07-31 03:26:34 +03:00
if ( subID = = 7 )
{
ms < < " (%s) " ;
ms . addReplacement ( MetaString : : RES_NAMES , producedResource ) ;
}
2013-02-09 01:42:46 +03:00
cb - > setHoverName ( this , & ms ) ;
2010-07-31 03:26:34 +03:00
InfoWindow iw ;
iw . soundID = soundBase : : FLAGMINE ;
iw . text . addTxt ( MetaString : : MINE_EVNTS , producedResource ) ; //not use subID, abandoned mines uses default mine texts
iw . player = player ;
2012-08-31 20:39:11 +03:00
iw . components . push_back ( Component ( Component : : RESOURCE , producedResource , producedQuantity , - 1 ) ) ;
2010-07-31 03:26:34 +03:00
cb - > showInfoDialog ( & iw ) ;
}
ui32 CGMine : : defaultResProduction ( )
{
switch ( producedResource )
{
2013-01-12 13:32:03 +03:00
case Res : : WOOD :
2013-01-03 15:19:20 +03:00
case Res : : ORE :
2010-07-31 03:26:34 +03:00
return 2 ;
2013-01-03 15:19:20 +03:00
case Res : : GOLD :
2010-07-31 03:26:34 +03:00
return 1000 ;
default :
return 1 ;
}
2008-12-27 03:01:59 +02:00
}
2013-04-20 14:34:01 +03:00
void CGMine : : battleFinished ( const CGHeroInstance * hero , const BattleResult & result ) const
{
if ( result . winner = = 0 ) //attacker won
{
if ( subID = = 7 )
{
showInfoDialog ( hero - > tempOwner , 85 , 0 ) ;
}
flagMine ( hero - > tempOwner ) ;
}
}
void CGMine : : blockingDialogAnswered ( const CGHeroInstance * hero , ui32 answer ) const
{
if ( answer )
cb - > startBattleI ( hero , this ) ;
}
2008-12-27 03:01:59 +02:00
void CGResource : : initObj ( )
{
blockVisit = true ;
2009-01-06 20:42:20 +02:00
hoverName = VLC - > generaltexth - > restypes [ subID ] ;
2008-12-27 03:01:59 +02:00
if ( ! amount )
{
switch ( subID )
{
case 6 :
2013-02-19 01:37:22 +03:00
amount = 500 + ( ran ( ) % 6 ) * 100 ;
2008-12-27 03:01:59 +02:00
break ;
case 0 : case 2 :
2013-02-19 01:37:22 +03:00
amount = 6 + ( ran ( ) % 5 ) ;
2008-12-27 03:01:59 +02:00
break ;
default :
2013-02-19 01:37:22 +03:00
amount = 3 + ( ran ( ) % 3 ) ;
2008-12-27 03:01:59 +02:00
break ;
}
}
}
void CGResource : : onHeroVisit ( const CGHeroInstance * h ) const
{
2010-05-02 21:20:26 +03:00
if ( stacksCount ( ) )
2008-12-27 03:01:59 +02:00
{
2009-01-11 00:08:18 +02:00
if ( message . size ( ) )
{
2009-04-11 04:32:50 +03:00
BlockingDialog ynd ( true , false ) ;
2009-01-11 00:08:18 +02:00
ynd . player = h - > getOwner ( ) ;
ynd . text < < message ;
2013-04-20 14:34:01 +03:00
cb - > showBlockingDialog ( & ynd ) ;
2009-01-11 00:08:18 +02:00
}
else
{
2013-04-20 14:34:01 +03:00
blockingDialogAnswered ( h , true ) ; //behave as if player accepted battle
2009-01-11 00:08:18 +02:00
}
2008-12-27 03:01:59 +02:00
}
2009-01-11 00:08:18 +02:00
else
{
if ( message . length ( ) )
{
InfoWindow iw ;
iw . player = h - > tempOwner ;
iw . text < < message ;
cb - > showInfoDialog ( & iw ) ;
}
collectRes ( h - > getOwner ( ) ) ;
}
}
2008-12-27 03:01:59 +02:00
2013-03-03 20:06:03 +03:00
void CGResource : : collectRes ( PlayerColor player ) const
2009-01-11 00:08:18 +02:00
{
2013-02-04 22:43:16 +03:00
cb - > giveResource ( player , static_cast < Res : : ERes > ( subID ) , amount ) ;
2008-12-27 03:01:59 +02:00
ShowInInfobox sii ;
2009-01-11 00:08:18 +02:00
sii . player = player ;
2012-08-31 20:39:11 +03:00
sii . c = Component ( Component : : RESOURCE , subID , amount , 0 ) ;
2013-01-12 13:32:03 +03:00
sii . text . addTxt ( MetaString : : ADVOB_TXT , 113 ) ;
2009-07-09 22:15:22 +03:00
sii . text . addReplacement ( MetaString : : RES_NAMES , subID ) ;
2008-12-27 03:01:59 +02:00
cb - > showCompInfo ( & sii ) ;
2013-02-09 00:17:39 +03:00
cb - > removeObject ( this ) ;
2008-12-27 03:01:59 +02:00
}
2013-04-20 14:34:01 +03:00
void CGResource : : battleFinished ( const CGHeroInstance * hero , const BattleResult & result ) const
2009-01-11 00:08:18 +02:00
{
2013-04-20 14:34:01 +03:00
if ( result . winner = = 0 ) //attacker won
collectRes ( hero - > getOwner ( ) ) ;
2009-01-11 00:08:18 +02:00
}
2013-04-20 14:34:01 +03:00
void CGResource : : blockingDialogAnswered ( const CGHeroInstance * hero , ui32 answer ) const
2009-01-11 00:08:18 +02:00
{
2013-04-20 14:34:01 +03:00
if ( answer )
cb - > startBattleI ( hero , this ) ;
2009-01-11 00:08:18 +02:00
}
2008-12-27 03:01:59 +02:00
void CGVisitableOPW : : newTurn ( ) const
{
2013-02-02 11:29:57 +03:00
if ( cb - > getDate ( Date : : DAY_OF_WEEK ) = = 1 ) //first day of week = 1
2008-12-27 03:01:59 +02:00
{
2010-05-02 21:20:26 +03:00
cb - > setObjProperty ( id , ObjProperty : : VISITED , false ) ;
2008-12-27 03:01:59 +02:00
MetaString ms ; //set text to "not visited"
ms < < std : : pair < ui8 , ui32 > ( 3 , ID ) < < " " < < std : : pair < ui8 , ui32 > ( 1 , 353 ) ;
2013-02-09 01:42:46 +03:00
cb - > setHoverName ( this , & ms ) ;
2008-12-27 03:01:59 +02:00
}
}
2013-03-03 20:06:03 +03:00
bool CGVisitableOPW : : wasVisited ( PlayerColor player ) const
2012-03-14 16:02:38 +03:00
{
2012-07-19 19:29:29 +03:00
return visited ; //TODO: other players should see object as unvisited
2012-03-14 16:02:38 +03:00
}
2008-12-27 03:01:59 +02:00
void CGVisitableOPW : : onHeroVisit ( const CGHeroInstance * h ) const
{
2012-07-06 23:19:54 +03:00
int mid = 0 , sound = 0 ;
2008-12-27 03:01:59 +02:00
switch ( ID )
{
2012-09-23 21:01:04 +03:00
case Obj : : MYSTICAL_GARDEN :
2009-04-24 00:09:10 +03:00
sound = soundBase : : experience ;
2008-12-27 03:01:59 +02:00
mid = 92 ;
break ;
2012-09-23 21:01:04 +03:00
case Obj : : WINDMILL :
2009-04-24 00:09:10 +03:00
sound = soundBase : : GENIE ;
2008-12-27 03:01:59 +02:00
mid = 170 ;
break ;
2012-09-23 21:01:04 +03:00
case Obj : : WATER_WHEEL :
2009-04-24 00:09:10 +03:00
sound = soundBase : : GENIE ;
2008-12-27 03:01:59 +02:00
mid = 164 ;
break ;
2012-07-06 23:19:54 +03:00
default :
assert ( 0 ) ;
2008-12-27 03:01:59 +02:00
}
if ( visited )
{
2012-09-23 21:01:04 +03:00
if ( ID ! = Obj : : WINDMILL )
2008-12-27 03:01:59 +02:00
mid + + ;
2012-07-19 21:52:44 +03:00
else
2008-12-27 03:01:59 +02:00
mid - - ;
2013-01-12 13:32:03 +03:00
showInfoDialog ( h , mid , sound ) ;
2008-12-27 03:01:59 +02:00
}
else
{
2012-08-31 20:39:11 +03:00
Component : : EComponentType type = Component : : RESOURCE ;
2013-02-04 22:43:16 +03:00
Res : : ERes sub = Res : : WOOD ;
int val = 0 ;
2012-08-31 20:39:11 +03:00
2008-12-27 03:01:59 +02:00
switch ( ID )
{
2012-09-23 21:01:04 +03:00
case Obj : : MYSTICAL_GARDEN :
2008-12-27 03:01:59 +02:00
if ( rand ( ) % 2 )
{
2013-02-04 22:43:16 +03:00
sub = Res : : GEMS ;
2008-12-27 03:01:59 +02:00
val = 5 ;
}
else
{
2013-02-04 22:43:16 +03:00
sub = Res : : GOLD ;
2008-12-27 03:01:59 +02:00
val = 500 ;
}
break ;
2012-09-23 21:01:04 +03:00
case Obj : : WINDMILL :
2008-12-27 03:01:59 +02:00
mid = 170 ;
2013-02-04 22:43:16 +03:00
sub = static_cast < Res : : ERes > ( ( rand ( ) % 5 ) + 1 ) ;
2008-12-27 03:01:59 +02:00
val = ( rand ( ) % 4 ) + 3 ;
break ;
2012-09-23 21:01:04 +03:00
case Obj : : WATER_WHEEL :
2008-12-27 03:01:59 +02:00
mid = 164 ;
2013-02-04 22:43:16 +03:00
sub = Res : : GOLD ;
2013-02-02 11:29:57 +03:00
if ( cb - > getDate ( Date : : DAY ) < 8 )
2008-12-27 03:01:59 +02:00
val = 500 ;
else
val = 1000 ;
}
2013-02-04 22:43:16 +03:00
cb - > giveResource ( h - > tempOwner , sub , val ) ;
2008-12-27 03:01:59 +02:00
InfoWindow iw ;
2009-04-24 00:09:10 +03:00
iw . soundID = sound ;
2008-12-27 03:01:59 +02:00
iw . player = h - > tempOwner ;
iw . components . push_back ( Component ( type , sub , val , 0 ) ) ;
2013-01-12 13:32:03 +03:00
iw . text . addTxt ( MetaString : : ADVOB_TXT , mid ) ;
2008-12-27 03:01:59 +02:00
cb - > showInfoDialog ( & iw ) ;
2010-05-02 21:20:26 +03:00
cb - > setObjProperty ( id , ObjProperty : : VISITED , true ) ;
2008-12-27 03:01:59 +02:00
MetaString ms ; //set text to "visited"
2013-01-13 15:40:24 +03:00
ms . addTxt ( MetaString : : OBJ_NAMES , ID ) ; ms < < " " ; ms . addTxt ( MetaString : : GENERAL_TXT , 352 ) ;
2013-02-09 01:42:46 +03:00
cb - > setHoverName ( this , & ms ) ;
2008-12-27 03:01:59 +02:00
}
}
2009-02-20 14:39:27 +02:00
void CGVisitableOPW : : setPropertyDer ( ui8 what , ui32 val )
{
2010-05-02 21:20:26 +03:00
if ( what = = ObjProperty : : VISITED )
2009-02-20 14:39:27 +02:00
visited = val ;
}
2008-12-27 03:01:59 +02:00
void CGTeleport : : onHeroVisit ( const CGHeroInstance * h ) const
{
2013-02-14 02:55:42 +03:00
ObjectInstanceID destinationid ;
2008-12-27 03:01:59 +02:00
switch ( ID )
{
2012-09-23 21:01:04 +03:00
case Obj : : MONOLITH1 : //one way - find corresponding exit monolith
2013-01-03 15:19:20 +03:00
if ( vstd : : contains ( objs , Obj : : MONOLITH2 ) & & vstd : : contains ( objs [ Obj : : MONOLITH2 ] , subID ) & & objs [ Obj : : MONOLITH2 ] [ subID ] . size ( ) )
destinationid = objs [ Obj : : MONOLITH2 ] [ subID ] [ rand ( ) % objs [ Obj : : MONOLITH2 ] [ subID ] . size ( ) ] ;
2008-12-27 03:01:59 +02:00
else
2013-04-09 17:31:36 +03:00
logGlobal - > warnStream ( ) < < " Cannot find corresponding exit monolith for " < < id ;
2008-12-27 03:01:59 +02:00
break ;
2012-09-23 21:01:04 +03:00
case Obj : : MONOLITH3 : //two way monolith - pick any other one
case Obj : : WHIRLPOOL : //Whirlpool
2010-06-07 16:11:08 +03:00
if ( vstd : : contains ( objs , ID ) & & vstd : : contains ( objs [ ID ] , subID ) & & objs [ ID ] [ subID ] . size ( ) > 1 )
{
while ( ( destinationid = objs [ ID ] [ subID ] [ rand ( ) % objs [ ID ] [ subID ] . size ( ) ] ) = = id ) ; //choose another exit
2012-09-23 21:01:04 +03:00
if ( ID = = Obj : : WHIRLPOOL )
2010-06-07 16:11:08 +03:00
{
if ( ! h - > hasBonusOfType ( Bonus : : WHIRLPOOL_PROTECTION ) )
{
2010-12-06 01:10:02 +02:00
if ( h - > Slots ( ) . size ( ) > 1 | | h - > Slots ( ) . begin ( ) - > second - > count > 1 )
2010-06-25 11:19:39 +03:00
{ //we can't remove last unit
2013-02-16 17:03:47 +03:00
SlotID targetstack = h - > Slots ( ) . begin ( ) - > first ; //slot numbers may vary
2013-06-29 16:05:48 +03:00
for ( auto i = h - > Slots ( ) . rbegin ( ) ; i ! = h - > Slots ( ) . rend ( ) ; i + + )
2010-06-07 16:11:08 +03:00
{
2010-12-06 01:10:02 +02:00
if ( h - > getPower ( targetstack ) > h - > getPower ( i - > first ) )
2010-06-25 11:19:39 +03:00
{
targetstack = ( i - > first ) ;
}
2010-06-07 16:11:08 +03:00
}
2010-12-06 01:10:02 +02:00
TQuantity countToTake = h - > getStackCount ( targetstack ) * 0.5 ;
2011-12-14 00:23:17 +03:00
vstd : : amax ( countToTake , 1 ) ;
2010-12-06 01:10:02 +02:00
2010-06-25 11:19:39 +03:00
2010-06-07 16:11:08 +03:00
InfoWindow iw ;
iw . player = h - > tempOwner ;
iw . text . addTxt ( MetaString : : ADVOB_TXT , 168 ) ;
2010-12-06 01:10:02 +02:00
iw . components . push_back ( Component ( CStackBasicDescriptor ( h - > getCreature ( targetstack ) , countToTake ) ) ) ;
2010-06-07 16:11:08 +03:00
cb - > showInfoDialog ( & iw ) ;
2010-12-06 01:10:02 +02:00
cb - > changeStackCount ( StackLocation ( h , targetstack ) , - countToTake ) ;
2010-06-07 16:11:08 +03:00
}
}
}
}
2008-12-27 03:01:59 +02:00
else
2013-04-09 17:31:36 +03:00
logGlobal - > warnStream ( ) < < " Cannot find corresponding exit monolith for " < < id ;
2008-12-27 03:01:59 +02:00
break ;
2012-09-23 21:01:04 +03:00
case Obj : : SUBTERRANEAN_GATE : //find nearest subterranean gate on the other level
2008-12-27 03:01:59 +02:00
{
2011-09-19 23:50:25 +03:00
destinationid = getMatchingGate ( id ) ;
2013-02-14 02:55:42 +03:00
if ( destinationid = = ObjectInstanceID ( ) ) //no exit
2010-02-10 05:35:48 +02:00
{
2013-01-12 13:32:03 +03:00
showInfoDialog ( h , 153 , 0 ) ; //Just inside the entrance you find a large pile of rubble blocking the tunnel. You leave discouraged.
2010-02-10 05:35:48 +02:00
}
2008-12-27 03:01:59 +02:00
break ;
}
}
2013-02-14 02:55:42 +03:00
if ( destinationid = = ObjectInstanceID ( ) )
2008-12-27 03:01:59 +02:00
{
2013-04-09 17:31:36 +03:00
logGlobal - > warnStream ( ) < < " Cannot find exit... (obj at " < < pos < < " ) :( " ;
2008-12-27 03:01:59 +02:00
return ;
}
2012-09-23 21:01:04 +03:00
if ( ID = = Obj : : WHIRLPOOL )
2010-08-29 13:13:56 +03:00
{
std : : set < int3 > tiles = cb - > getObj ( destinationid ) - > getBlockedPos ( ) ;
2013-06-29 16:05:48 +03:00
auto it = tiles . begin ( ) ;
2010-08-29 13:13:56 +03:00
std : : advance ( it , rand ( ) % tiles . size ( ) ) ; //picking random element of set is tiring
cb - > moveHero ( h - > id , * it + int3 ( 1 , 0 , 0 ) , true ) ;
}
2010-06-25 11:19:39 +03:00
else
cb - > moveHero ( h - > id , CGHeroInstance : : convertPosition ( cb - > getObj ( destinationid ) - > pos , true ) - getVisitableOffset ( ) , true ) ;
2008-12-27 03:01:59 +02:00
}
void CGTeleport : : initObj ( )
{
2009-09-07 05:29:44 +03:00
int si = subID ;
2010-06-07 16:11:08 +03:00
switch ( ID )
{
2012-09-23 21:01:04 +03:00
case Obj : : SUBTERRANEAN_GATE : //ignore subterranean gates subid
case Obj : : WHIRLPOOL :
2010-06-07 16:11:08 +03:00
{
si = 0 ;
break ;
}
2012-09-23 21:01:04 +03:00
default :
break ;
2010-06-07 16:11:08 +03:00
}
2009-09-07 05:29:44 +03:00
objs [ ID ] [ si ] . push_back ( id ) ;
}
void CGTeleport : : postInit ( ) //matches subterranean gates into pairs
{
//split on underground and surface gates
std : : vector < const CGObjectInstance * > gatesSplit [ 2 ] ; //surface and underground gates
2013-06-29 16:05:48 +03:00
for ( auto & elem : objs [ Obj : : SUBTERRANEAN_GATE ] [ 0 ] )
2009-09-07 05:29:44 +03:00
{
2013-06-29 16:05:48 +03:00
const CGObjectInstance * hlp = cb - > getObj ( elem ) ;
2009-09-07 05:29:44 +03:00
gatesSplit [ hlp - > pos . z ] . push_back ( hlp ) ;
}
//sort by position
2013-06-26 14:18:27 +03:00
std : : sort ( gatesSplit [ 0 ] . begin ( ) , gatesSplit [ 0 ] . end ( ) , [ ] ( const CGObjectInstance * a , const CGObjectInstance * b )
{
return a - > pos < b - > pos ;
} ) ;
2009-09-07 05:29:44 +03:00
for ( size_t i = 0 ; i < gatesSplit [ 0 ] . size ( ) ; i + + )
{
const CGObjectInstance * cur = gatesSplit [ 0 ] [ i ] ;
//find nearest underground exit
std : : pair < int , double > best ( - 1 , 150000 ) ; //pair<pos_in_vector, distance>
for ( int j = 0 ; j < gatesSplit [ 1 ] . size ( ) ; j + + )
{
const CGObjectInstance * checked = gatesSplit [ 1 ] [ j ] ;
if ( ! checked )
continue ;
double hlp = checked - > pos . dist2d ( cur - > pos ) ;
if ( hlp < best . second )
{
best . first = j ;
best . second = hlp ;
}
}
2010-02-10 05:35:48 +02:00
if ( best . first > = 0 ) //found pair
{
2013-02-14 02:55:42 +03:00
gates . push_back ( std : : make_pair ( cur - > id , gatesSplit [ 1 ] [ best . first ] - > id ) ) ;
2013-06-26 14:18:27 +03:00
gatesSplit [ 1 ] [ best . first ] = nullptr ;
2010-02-10 05:35:48 +02:00
}
else
{
2013-02-14 02:55:42 +03:00
gates . push_back ( std : : make_pair ( cur - > id , ObjectInstanceID ( ) ) ) ;
2010-02-10 05:35:48 +02:00
}
2009-09-07 05:29:44 +03:00
}
2013-02-16 17:03:47 +03:00
objs . erase ( Obj : : SUBTERRANEAN_GATE ) ;
2008-12-27 03:01:59 +02:00
}
2013-02-14 02:55:42 +03:00
ObjectInstanceID CGTeleport : : getMatchingGate ( ObjectInstanceID id )
2011-09-19 23:50:25 +03:00
{
2013-06-29 16:05:48 +03:00
for ( auto & gate : gates )
2011-09-19 23:50:25 +03:00
{
2013-06-29 16:05:48 +03:00
if ( gate . first = = id )
return gate . second ;
if ( gate . second = = id )
return gate . first ;
2011-09-19 23:50:25 +03:00
}
2013-02-14 02:55:42 +03:00
return ObjectInstanceID ( ) ;
2011-09-19 23:50:25 +03:00
}
2008-12-27 03:01:59 +02:00
void CGArtifact : : initObj ( )
{
blockVisit = true ;
2012-09-23 21:01:04 +03:00
if ( ID = = Obj : : ARTIFACT )
2010-12-26 16:34:11 +02:00
{
2010-06-26 19:02:10 +03:00
hoverName = VLC - > arth - > artifacts [ subID ] - > Name ( ) ;
2010-12-26 16:34:11 +02:00
if ( ! storedArtifact - > artType )
storedArtifact - > setType ( VLC - > arth - > artifacts [ subID ] ) ;
}
2012-09-23 21:01:04 +03:00
if ( ID = = Obj : : SPELL_SCROLL )
2010-11-10 02:06:25 +02:00
subID = 1 ;
2013-03-30 23:09:50 +03:00
2010-12-26 16:34:11 +02:00
assert ( storedArtifact - > artType ) ;
2011-07-13 21:39:02 +03:00
assert ( storedArtifact - > getParentNodes ( ) . size ( ) ) ;
2013-03-30 23:09:50 +03:00
//assert(storedArtifact->artType->id == subID); //this does not stop desync
2008-12-27 03:01:59 +02:00
}
void CGArtifact : : onHeroVisit ( const CGHeroInstance * h ) const
2009-02-03 07:28:05 +02:00
{
2010-05-02 21:20:26 +03:00
if ( ! stacksCount ( ) )
2009-02-03 07:28:05 +02:00
{
2010-11-10 02:06:25 +02:00
InfoWindow iw ;
iw . player = h - > tempOwner ;
switch ( ID )
2009-03-19 16:17:19 +02:00
{
2012-09-23 21:01:04 +03:00
case Obj : : ARTIFACT :
2010-11-10 02:06:25 +02:00
{
2011-03-12 23:55:31 +02:00
iw . soundID = soundBase : : treasure ; //play sound only for non-scroll arts
2012-08-31 20:39:11 +03:00
iw . components . push_back ( Component ( Component : : ARTIFACT , subID , 0 , 0 ) ) ;
2010-11-10 02:06:25 +02:00
if ( message . length ( ) )
iw . text < < message ;
else
2013-01-23 00:50:43 +03:00
{
if ( VLC - > arth - > artifacts [ subID ] - > EventText ( ) . size ( ) )
iw . text < < std : : pair < ui8 , ui32 > ( MetaString : : ART_EVNTS , subID ) ;
else //fix for mod artifacts with no event text
{
iw . text . addTxt ( MetaString : : ADVOB_TXT , 183 ) ; //% has found treasure
iw . text . addReplacement ( h - > name ) ;
}
}
2010-11-10 02:06:25 +02:00
}
break ;
2012-09-23 21:01:04 +03:00
case Obj : : SPELL_SCROLL :
2011-03-12 23:55:31 +02:00
{
int spellID = storedArtifact - > getGivenSpellID ( ) ;
iw . components . push_back ( Component ( Component : : SPELL , spellID , 0 , 0 ) ) ;
iw . text . addTxt ( MetaString : : ADVOB_TXT , 135 ) ;
iw . text . addReplacement ( MetaString : : SPELL_NAME , spellID ) ;
}
2010-11-10 02:06:25 +02:00
break ;
2009-03-19 16:17:19 +02:00
}
2010-11-10 02:06:25 +02:00
cb - > showInfoDialog ( & iw ) ;
2009-02-03 07:28:05 +02:00
pick ( h ) ;
}
else
{
if ( message . size ( ) )
{
2009-04-11 04:32:50 +03:00
BlockingDialog ynd ( true , false ) ;
2009-02-03 07:28:05 +02:00
ynd . player = h - > getOwner ( ) ;
ynd . text < < message ;
2013-04-20 14:34:01 +03:00
cb - > showBlockingDialog ( & ynd ) ;
2009-02-03 07:28:05 +02:00
}
else
{
2013-04-20 14:34:01 +03:00
blockingDialogAnswered ( h , true ) ;
2009-02-03 07:28:05 +02:00
}
}
}
void CGArtifact : : pick ( const CGHeroInstance * h ) const
2008-12-27 03:01:59 +02:00
{
2013-02-07 02:24:43 +03:00
cb - > giveHeroArtifact ( h , storedArtifact , ArtifactPosition : : FIRST_AVAILABLE ) ;
2013-02-09 00:17:39 +03:00
cb - > removeObject ( this ) ;
2008-12-27 03:01:59 +02:00
}
2013-04-20 14:34:01 +03:00
void CGArtifact : : battleFinished ( const CGHeroInstance * hero , const BattleResult & result ) const
2009-02-03 07:28:05 +02:00
{
2013-04-20 14:34:01 +03:00
if ( result . winner = = 0 ) //attacker won
pick ( hero ) ;
2009-02-03 07:28:05 +02:00
}
2013-04-20 14:34:01 +03:00
void CGArtifact : : blockingDialogAnswered ( const CGHeroInstance * hero , ui32 answer ) const
2009-02-03 07:28:05 +02:00
{
2013-04-20 14:34:01 +03:00
if ( answer )
cb - > startBattleI ( hero , this ) ;
2009-02-03 07:28:05 +02:00
}
2013-04-20 14:34:01 +03:00
2008-12-27 03:01:59 +02:00
void CGPickable : : initObj ( )
{
blockVisit = true ;
switch ( ID )
{
2012-09-23 21:01:04 +03:00
case Obj : : CAMPFIRE :
2008-12-27 03:01:59 +02:00
val2 = ( ran ( ) % 3 ) + 4 ; //4 - 6
val1 = val2 * 100 ;
type = ran ( ) % 6 ; //given resource
break ;
2012-09-23 21:01:04 +03:00
case Obj : : FLOTSAM :
2009-07-19 06:10:24 +03:00
switch ( type = ran ( ) % 4 )
{
case 0 :
val1 = val2 = 0 ;
break ;
case 1 :
val1 = 5 ;
val2 = 0 ;
break ;
case 2 :
val1 = 5 ;
val2 = 200 ;
break ;
case 3 :
val1 = 10 ;
val2 = 500 ;
break ;
}
break ;
2012-09-23 21:01:04 +03:00
case Obj : : SEA_CHEST :
2009-07-19 06:10:24 +03:00
{
int hlp = ran ( ) % 100 ;
if ( hlp < 20 )
{
val1 = 0 ;
type = 0 ;
}
else if ( hlp < 90 )
{
val1 = 1500 ;
type = 2 ;
}
else
{
val1 = 1000 ;
2009-10-24 22:21:32 +03:00
val2 = cb - > getRandomArt ( CArtifact : : ART_TREASURE ) ;
2009-07-19 06:10:24 +03:00
type = 1 ;
}
}
break ;
2012-09-23 21:01:04 +03:00
case Obj : : SHIPWRECK_SURVIVOR :
2009-07-19 06:10:24 +03:00
{
int hlp = ran ( ) % 100 ;
if ( hlp < 55 )
2009-10-24 22:21:32 +03:00
val1 = cb - > getRandomArt ( CArtifact : : ART_TREASURE ) ;
2009-07-19 06:10:24 +03:00
else if ( hlp < 75 )
2009-10-24 22:21:32 +03:00
val1 = cb - > getRandomArt ( CArtifact : : ART_MINOR ) ;
2009-07-19 06:10:24 +03:00
else if ( hlp < 95 )
2009-10-24 22:21:32 +03:00
val1 = cb - > getRandomArt ( CArtifact : : ART_MAJOR ) ;
2009-07-19 06:10:24 +03:00
else
2009-10-24 22:21:32 +03:00
val1 = cb - > getRandomArt ( CArtifact : : ART_RELIC ) ;
2009-07-19 06:10:24 +03:00
}
break ;
2012-09-23 21:01:04 +03:00
case Obj : : TREASURE_CHEST :
2008-12-27 03:01:59 +02:00
{
int hlp = ran ( ) % 100 ;
if ( hlp > = 95 )
{
type = 1 ;
2009-10-24 22:21:32 +03:00
val1 = cb - > getRandomArt ( CArtifact : : ART_TREASURE ) ;
2008-12-27 03:01:59 +02:00
return ;
}
else if ( hlp > = 65 )
{
val1 = 2000 ;
}
else if ( hlp > = 33 )
{
val1 = 1500 ;
}
else
{
val1 = 1000 ;
}
val2 = val1 - 500 ;
type = 0 ;
break ;
}
}
}
void CGPickable : : onHeroVisit ( const CGHeroInstance * h ) const
{
switch ( ID )
{
2012-09-23 21:01:04 +03:00
case Obj : : CAMPFIRE :
2008-12-27 03:01:59 +02:00
{
2013-02-04 22:43:16 +03:00
cb - > giveResource ( h - > tempOwner , static_cast < Res : : ERes > ( type ) , val2 ) ; //non-gold resource
2012-08-31 20:39:11 +03:00
cb - > giveResource ( h - > tempOwner , Res : : GOLD , val1 ) ; //gold
2008-12-27 03:01:59 +02:00
InfoWindow iw ;
2009-04-24 00:09:10 +03:00
iw . soundID = soundBase : : experience ;
2008-12-27 03:01:59 +02:00
iw . player = h - > tempOwner ;
2012-08-31 20:39:11 +03:00
iw . components . push_back ( Component ( Component : : RESOURCE , Res : : GOLD , val1 , 0 ) ) ;
iw . components . push_back ( Component ( Component : : RESOURCE , type , val2 , 0 ) ) ;
2013-01-12 13:32:03 +03:00
iw . text . addTxt ( MetaString : : ADVOB_TXT , 23 ) ;
2008-12-27 03:01:59 +02:00
cb - > showInfoDialog ( & iw ) ;
break ;
}
2012-09-23 21:01:04 +03:00
case Obj : : FLOTSAM :
2009-07-19 06:10:24 +03:00
{
2013-01-12 16:53:02 +03:00
cb - > giveResource ( h - > tempOwner , Res : : WOOD , val1 ) ; //wood
cb - > giveResource ( h - > tempOwner , Res : : GOLD , val2 ) ; //gold
2009-07-19 06:10:24 +03:00
InfoWindow iw ;
iw . soundID = soundBase : : GENIE ;
iw . player = h - > tempOwner ;
if ( val1 )
2012-08-31 20:39:11 +03:00
iw . components . push_back ( Component ( Component : : RESOURCE , Res : : WOOD , val1 , 0 ) ) ;
2009-07-19 06:10:24 +03:00
if ( val2 )
2012-08-31 20:39:11 +03:00
iw . components . push_back ( Component ( Component : : RESOURCE , Res : : GOLD , val2 , 0 ) ) ;
2009-07-19 06:10:24 +03:00
iw . text . addTxt ( MetaString : : ADVOB_TXT , 51 + type ) ;
cb - > showInfoDialog ( & iw ) ;
break ;
}
2012-09-23 21:01:04 +03:00
case Obj : : SEA_CHEST :
2009-07-19 06:10:24 +03:00
{
InfoWindow iw ;
iw . soundID = soundBase : : chest ;
iw . player = h - > tempOwner ;
iw . text . addTxt ( MetaString : : ADVOB_TXT , 116 + type ) ;
if ( val1 ) //there is gold
{
2012-08-31 20:39:11 +03:00
iw . components . push_back ( Component ( Component : : RESOURCE , Res : : GOLD , val1 , 0 ) ) ;
2013-02-04 22:43:16 +03:00
cb - > giveResource ( h - > tempOwner , Res : : GOLD , val1 ) ;
2009-07-19 06:10:24 +03:00
}
if ( type = = 1 ) //art
{
//TODO: what if no space in backpack?
2012-08-31 20:39:11 +03:00
iw . components . push_back ( Component ( Component : : ARTIFACT , val2 , 1 , 0 ) ) ;
2009-07-19 06:10:24 +03:00
iw . text . addReplacement ( MetaString : : ART_NAMES , val2 ) ;
2013-02-07 02:24:43 +03:00
cb - > giveHeroNewArtifact ( h , VLC - > arth - > artifacts [ val2 ] , ArtifactPosition : : FIRST_AVAILABLE ) ;
2009-07-19 06:10:24 +03:00
}
cb - > showInfoDialog ( & iw ) ;
break ;
}
2012-09-23 21:01:04 +03:00
case Obj : : SHIPWRECK_SURVIVOR :
2009-07-19 06:10:24 +03:00
{
InfoWindow iw ;
iw . soundID = soundBase : : experience ;
iw . player = h - > tempOwner ;
2012-08-31 20:39:11 +03:00
iw . components . push_back ( Component ( Component : : ARTIFACT , val1 , 1 , 0 ) ) ;
2009-07-19 06:10:24 +03:00
iw . text . addTxt ( MetaString : : ADVOB_TXT , 125 ) ;
iw . text . addReplacement ( MetaString : : ART_NAMES , val1 ) ;
2013-02-07 02:24:43 +03:00
cb - > giveHeroNewArtifact ( h , VLC - > arth - > artifacts [ val1 ] , ArtifactPosition : : FIRST_AVAILABLE ) ;
2009-07-19 06:10:24 +03:00
cb - > showInfoDialog ( & iw ) ;
break ;
}
2012-09-23 21:01:04 +03:00
case Obj : : TREASURE_CHEST :
2008-12-27 03:01:59 +02:00
{
if ( subID ) //not OH3 treasure chest
{
2013-04-09 17:31:36 +03:00
logGlobal - > warnStream ( ) < < " Not supported WoG treasure chest! " ;
2012-07-19 21:52:44 +03:00
return ;
2008-12-27 03:01:59 +02:00
}
if ( type ) //there is an artifact
{
2013-02-07 02:24:43 +03:00
cb - > giveHeroNewArtifact ( h , VLC - > arth - > artifacts [ val1 ] , ArtifactPosition : : FIRST_AVAILABLE ) ;
2008-12-27 03:01:59 +02:00
InfoWindow iw ;
2009-04-24 00:09:10 +03:00
iw . soundID = soundBase : : treasure ;
2008-12-27 03:01:59 +02:00
iw . player = h - > tempOwner ;
2012-08-31 20:39:11 +03:00
iw . components . push_back ( Component ( Component : : ARTIFACT , val1 , 1 , 0 ) ) ;
2013-01-12 13:32:03 +03:00
iw . text . addTxt ( MetaString : : ADVOB_TXT , 145 ) ;
2009-07-09 22:15:22 +03:00
iw . text . addReplacement ( MetaString : : ART_NAMES , val1 ) ;
2008-12-27 03:01:59 +02:00
cb - > showInfoDialog ( & iw ) ;
break ;
}
else
{
2009-04-11 04:32:50 +03:00
BlockingDialog sd ( false , true ) ;
2008-12-27 03:01:59 +02:00
sd . player = h - > tempOwner ;
2013-01-12 13:32:03 +03:00
sd . text . addTxt ( MetaString : : ADVOB_TXT , 146 ) ;
2012-08-31 20:39:11 +03:00
sd . components . push_back ( Component ( Component : : RESOURCE , Res : : GOLD , val1 , 0 ) ) ;
2012-09-23 21:01:04 +03:00
TExpType expVal = h - > calculateXp ( val2 ) ;
2012-08-31 20:39:11 +03:00
sd . components . push_back ( Component ( Component : : EXPERIENCE , 0 , expVal , 0 ) ) ;
2009-04-22 21:48:56 +03:00
sd . soundID = soundBase : : chest ;
2013-04-20 14:34:01 +03:00
cb - > showBlockingDialog ( & sd ) ;
2008-12-27 03:01:59 +02:00
return ;
}
}
}
2013-02-09 00:17:39 +03:00
cb - > removeObject ( this ) ;
2008-12-27 03:01:59 +02:00
}
2013-04-20 14:34:01 +03:00
void CGPickable : : blockingDialogAnswered ( const CGHeroInstance * hero , ui32 answer ) const
2008-12-27 03:01:59 +02:00
{
2013-04-20 14:34:01 +03:00
switch ( answer )
2008-12-27 03:01:59 +02:00
{
2009-04-11 04:32:50 +03:00
case 1 : //player pick gold
2013-04-20 14:34:01 +03:00
cb - > giveResource ( hero - > tempOwner , Res : : GOLD , val1 ) ;
2008-12-27 03:01:59 +02:00
break ;
2009-04-11 04:32:50 +03:00
case 2 : //player pick exp
2013-04-20 14:34:01 +03:00
cb - > changePrimSkill ( hero , PrimarySkill : : EXPERIENCE , hero - > calculateXp ( val2 ) ) ;
2008-12-27 03:01:59 +02:00
break ;
default :
2012-04-22 10:32:45 +03:00
throw std : : runtime_error ( " Unhandled treasure choice " ) ;
2008-12-27 03:01:59 +02:00
}
2013-02-09 00:17:39 +03:00
cb - > removeObject ( this ) ;
2009-01-11 00:08:18 +02:00
}
2009-12-31 13:43:37 +02:00
bool CQuest : : checkQuest ( const CGHeroInstance * h ) const
{
switch ( missionType )
{
case MISSION_NONE :
return true ;
case MISSION_LEVEL :
if ( m13489val < = h - > level )
return true ;
return false ;
case MISSION_PRIMARY_STAT :
2013-02-06 13:16:44 +03:00
for ( int i = 0 ; i < GameConstants : : PRIMARY_SKILLS ; + + i )
2009-12-31 13:43:37 +02:00
{
2013-02-06 13:16:44 +03:00
if ( h - > getPrimSkillLevel ( static_cast < PrimarySkill : : PrimarySkill > ( i ) ) < m2stats [ i ] )
2009-12-31 13:43:37 +02:00
return false ;
}
return true ;
case MISSION_KILL_HERO :
case MISSION_KILL_CREATURE :
2011-02-11 14:27:38 +02:00
if ( ! h - > cb - > getObjByQuestIdentifier ( m13489val ) )
2010-02-07 18:05:27 +02:00
return true ;
return false ;
2009-12-31 13:43:37 +02:00
case MISSION_ART :
2013-06-29 16:05:48 +03:00
for ( auto & elem : m5arts )
2009-12-31 13:43:37 +02:00
{
2013-06-29 16:05:48 +03:00
if ( h - > hasArt ( elem ) )
2009-12-31 13:43:37 +02:00
continue ;
return false ; //if the artifact was not found
}
return true ;
case MISSION_ARMY :
2010-01-01 14:15:20 +02:00
{
2010-11-22 02:34:46 +02:00
std : : vector < CStackBasicDescriptor > : : const_iterator cre ;
TSlots : : const_iterator it ;
2010-01-01 14:15:20 +02:00
ui32 count ;
for ( cre = m6creatures . begin ( ) ; cre ! = m6creatures . end ( ) ; + + cre )
{
2010-05-02 21:20:26 +03:00
for ( count = 0 , it = h - > Slots ( ) . begin ( ) ; it ! = h - > Slots ( ) . end ( ) ; + + it )
2010-01-01 14:15:20 +02:00
{
2010-11-22 02:34:46 +02:00
if ( it - > second - > type = = cre - > type )
count + = it - > second - > count ;
2010-01-01 14:15:20 +02:00
}
2010-11-22 02:34:46 +02:00
if ( count < cre - > count ) //not enough creatures of this kind
2010-01-01 14:15:20 +02:00
return false ;
}
}
return true ;
2009-12-31 13:43:37 +02:00
case MISSION_RESOURCES :
2013-02-09 15:56:35 +03:00
for ( Res : : ERes i = Res : : WOOD ; i < = Res : : GOLD ; vstd : : advance ( i , + 1 ) ) //including Mithril ?
2009-12-31 13:43:37 +02:00
{ //Quest has no direct access to callback
2012-07-19 21:52:44 +03:00
if ( h - > cb - > getResource ( h - > tempOwner , i ) < m7resources [ i ] )
2009-12-31 13:43:37 +02:00
return false ;
}
return true ;
case MISSION_HERO :
2013-05-19 01:30:48 +03:00
if ( m13489val = = h - > type - > ID . getNum ( ) )
2009-12-31 13:43:37 +02:00
return true ;
return false ;
case MISSION_PLAYER :
2013-03-03 20:06:03 +03:00
if ( m13489val = = h - > getOwner ( ) . getNum ( ) )
2009-12-31 13:43:37 +02:00
return true ;
return false ;
default :
return false ;
}
}
2012-07-08 09:33:41 +03:00
void CQuest : : getVisitText ( MetaString & iwText , std : : vector < Component > & components , bool isCustom , bool firstVisit , const CGHeroInstance * h ) const
{
std : : string text ;
bool failRequirements = ( h ? ! checkQuest ( h ) : true ) ;
2012-07-19 21:52:44 +03:00
if ( firstVisit )
2012-07-08 09:33:41 +03:00
{
isCustom = isCustomFirst ;
2013-07-23 18:03:01 +03:00
iwText < < ( text = firstVisitText ) ;
2012-07-08 09:33:41 +03:00
}
else if ( failRequirements )
{
isCustom = isCustomNext ;
2013-07-23 18:03:01 +03:00
iwText < < ( text = nextVisitText ) ;
2012-07-08 09:33:41 +03:00
}
switch ( missionType )
{
case MISSION_LEVEL :
2013-07-23 18:03:01 +03:00
components . push_back ( Component ( Component : : EXPERIENCE , 0 , m13489val , 0 ) ) ;
2013-07-23 08:41:42 +03:00
if ( ! isCustom )
iwText . addReplacement ( m13489val ) ;
break ;
2012-07-08 09:33:41 +03:00
case MISSION_PRIMARY_STAT :
{
MetaString loot ;
for ( int i = 0 ; i < 4 ; + + i )
{
if ( m2stats [ i ] )
{
components . push_back ( Component ( Component : : PRIM_SKILL , i , m2stats [ i ] , 0 ) ) ;
loot < < " %d %s " ;
loot . addReplacement ( m2stats [ i ] ) ;
loot . addReplacement ( VLC - > generaltexth - > primarySkillNames [ i ] ) ;
2012-07-19 21:52:44 +03:00
}
2012-07-08 09:33:41 +03:00
}
if ( ! isCustom )
iwText . addReplacement ( loot . buildList ( ) ) ;
}
break ;
case MISSION_KILL_HERO :
components . push_back ( Component ( Component : : HERO , heroPortrait , 0 , 0 ) ) ;
if ( ! isCustom )
addReplacements ( iwText , text ) ;
break ;
case MISSION_HERO :
components . push_back ( Component ( Component : : HERO , m13489val , 0 , 0 ) ) ;
if ( ! isCustom )
iwText . addReplacement ( VLC - > heroh - > heroes [ m13489val ] - > name ) ;
break ;
case MISSION_KILL_CREATURE :
{
components . push_back ( Component ( stackToKill ) ) ;
if ( ! isCustom )
2013-07-23 18:03:01 +03:00
{
2012-07-08 09:33:41 +03:00
addReplacements ( iwText , text ) ;
2013-07-23 18:03:01 +03:00
}
2012-07-08 09:33:41 +03:00
}
break ;
case MISSION_ART :
{
MetaString loot ;
2013-06-29 16:05:48 +03:00
for ( auto & elem : m5arts )
2012-07-08 09:33:41 +03:00
{
2013-06-29 16:05:48 +03:00
components . push_back ( Component ( Component : : ARTIFACT , elem , 0 , 0 ) ) ;
2012-07-08 09:33:41 +03:00
loot < < " %s " ;
2013-06-29 16:05:48 +03:00
loot . addReplacement ( MetaString : : ART_NAMES , elem ) ;
2012-07-08 09:33:41 +03:00
}
if ( ! isCustom )
iwText . addReplacement ( loot . buildList ( ) ) ;
}
break ;
case MISSION_ARMY :
{
MetaString loot ;
2013-06-29 16:05:48 +03:00
for ( auto & elem : m6creatures )
2012-07-08 09:33:41 +03:00
{
2013-06-29 16:05:48 +03:00
components . push_back ( Component ( elem ) ) ;
2012-07-08 09:33:41 +03:00
loot < < " %s " ;
2013-06-29 16:05:48 +03:00
loot . addReplacement ( elem ) ;
2012-07-08 09:33:41 +03:00
}
if ( ! isCustom )
iwText . addReplacement ( loot . buildList ( ) ) ;
}
break ;
case MISSION_RESOURCES :
{
MetaString loot ;
for ( int i = 0 ; i < 7 ; + + i )
{
if ( m7resources [ i ] )
{
components . push_back ( Component ( Component : : RESOURCE , i , m7resources [ i ] , 0 ) ) ;
loot < < " %d %s " ;
loot . addReplacement ( m7resources [ i ] ) ;
loot . addReplacement ( MetaString : : RES_NAMES , i ) ;
}
}
if ( ! isCustom )
iwText . addReplacement ( loot . buildList ( ) ) ;
}
break ;
case MISSION_PLAYER :
components . push_back ( Component ( Component : : FLAG , m13489val , 0 , 0 ) ) ;
if ( ! isCustom )
iwText . addReplacement ( VLC - > generaltexth - > colors [ m13489val ] ) ;
break ;
}
}
void CQuest : : getRolloverText ( MetaString & ms , bool onHover ) const
{
if ( onHover )
ms < < " \n \n " ;
ms < < VLC - > generaltexth - > quests [ missionType - 1 ] [ onHover ? 3 : 4 ] [ textOption ] ;
switch ( missionType )
{
case MISSION_LEVEL :
ms . addReplacement ( m13489val ) ;
break ;
case MISSION_PRIMARY_STAT :
{
MetaString loot ;
for ( int i = 0 ; i < 4 ; + + i )
{
if ( m2stats [ i ] )
{
loot < < " %d %s " ;
loot . addReplacement ( m2stats [ i ] ) ;
loot . addReplacement ( VLC - > generaltexth - > primarySkillNames [ i ] ) ;
2012-07-19 21:52:44 +03:00
}
2012-07-08 09:33:41 +03:00
}
ms . addReplacement ( loot . buildList ( ) ) ;
}
break ;
case MISSION_KILL_HERO :
ms . addReplacement ( heroName ) ;
break ;
case MISSION_KILL_CREATURE :
ms . addReplacement ( stackToKill ) ;
break ;
case MISSION_ART :
{
MetaString loot ;
2013-06-29 16:05:48 +03:00
for ( auto & elem : m5arts )
2012-07-08 09:33:41 +03:00
{
loot < < " %s " ;
2013-06-29 16:05:48 +03:00
loot . addReplacement ( MetaString : : ART_NAMES , elem ) ;
2012-07-08 09:33:41 +03:00
}
ms . addReplacement ( loot . buildList ( ) ) ;
}
break ;
case MISSION_ARMY :
{
MetaString loot ;
2013-06-29 16:05:48 +03:00
for ( auto & elem : m6creatures )
2012-07-08 09:33:41 +03:00
{
loot < < " %s " ;
2013-06-29 16:05:48 +03:00
loot . addReplacement ( elem ) ;
2012-07-08 09:33:41 +03:00
}
ms . addReplacement ( loot . buildList ( ) ) ;
}
break ;
case MISSION_RESOURCES :
{
MetaString loot ;
for ( int i = 0 ; i < 7 ; + + i )
{
if ( m7resources [ i ] )
{
loot < < " %d %s " ;
loot . addReplacement ( m7resources [ i ] ) ;
loot . addReplacement ( MetaString : : RES_NAMES , i ) ;
}
}
ms . addReplacement ( loot . buildList ( ) ) ;
}
break ;
case MISSION_HERO :
ms . addReplacement ( VLC - > heroh - > heroes [ m13489val ] - > name ) ;
break ;
case MISSION_PLAYER :
ms . addReplacement ( VLC - > generaltexth - > colors [ m13489val ] ) ;
break ;
default :
break ;
}
}
void CQuest : : getCompletionText ( MetaString & iwText , std : : vector < Component > & components , bool isCustom , const CGHeroInstance * h ) const
{
iwText < < completedText ;
switch ( missionType )
{
case CQuest : : MISSION_LEVEL :
if ( ! isCustomComplete )
iwText . addReplacement ( m13489val ) ;
break ;
case CQuest : : MISSION_PRIMARY_STAT :
if ( vstd : : contains ( completedText , ' % ' ) ) //there's one case when there's nothing to replace
{
MetaString loot ;
for ( int i = 0 ; i < 4 ; + + i )
{
if ( m2stats [ i ] )
{
loot < < " %d %s " ;
loot . addReplacement ( m2stats [ i ] ) ;
loot . addReplacement ( VLC - > generaltexth - > primarySkillNames [ i ] ) ;
}
}
if ( ! isCustomComplete )
iwText . addReplacement ( loot . buildList ( ) ) ;
}
break ;
case CQuest : : MISSION_ART :
{
MetaString loot ;
2013-06-29 16:05:48 +03:00
for ( auto & elem : m5arts )
2012-07-08 09:33:41 +03:00
{
loot < < " %s " ;
2013-06-29 16:05:48 +03:00
loot . addReplacement ( MetaString : : ART_NAMES , elem ) ;
2012-07-08 09:33:41 +03:00
}
if ( ! isCustomComplete )
iwText . addReplacement ( loot . buildList ( ) ) ;
}
break ;
case CQuest : : MISSION_ARMY :
{
MetaString loot ;
2013-06-29 16:05:48 +03:00
for ( auto & elem : m6creatures )
2012-07-08 09:33:41 +03:00
{
loot < < " %s " ;
2013-06-29 16:05:48 +03:00
loot . addReplacement ( elem ) ;
2012-07-08 09:33:41 +03:00
}
if ( ! isCustomComplete )
iwText . addReplacement ( loot . buildList ( ) ) ;
}
break ;
case CQuest : : MISSION_RESOURCES :
{
MetaString loot ;
for ( int i = 0 ; i < 7 ; + + i )
{
if ( m7resources [ i ] )
{
loot < < " %d %s " ;
loot . addReplacement ( m7resources [ i ] ) ;
loot . addReplacement ( MetaString : : RES_NAMES , i ) ;
}
}
if ( ! isCustomComplete )
iwText . addReplacement ( loot . buildList ( ) ) ;
}
break ;
case MISSION_KILL_HERO :
case MISSION_KILL_CREATURE :
if ( ! isCustomComplete )
addReplacements ( iwText , completedText ) ;
break ;
case MISSION_HERO :
if ( ! isCustomComplete )
iwText . addReplacement ( VLC - > heroh - > heroes [ m13489val ] - > name ) ;
break ;
case MISSION_PLAYER :
if ( ! isCustomComplete )
iwText . addReplacement ( VLC - > generaltexth - > colors [ m13489val ] ) ;
break ;
}
}
2012-07-19 12:10:55 +03:00
void CGSeerHut : : setObjToKill ( )
{
2012-10-03 17:49:29 +03:00
if ( quest - > missionType = = CQuest : : MISSION_KILL_CREATURE )
2012-07-19 12:10:55 +03:00
{
2013-02-16 17:03:47 +03:00
quest - > stackToKill = getCreatureToKill ( false ) - > getStack ( SlotID ( 0 ) ) ; //FIXME: stacks tend to dissapear (desync?) on server :?
2012-10-03 17:49:29 +03:00
assert ( quest - > stackToKill . type ) ;
quest - > stackToKill . count = 0 ; //no count in info window
quest - > stackDirection = checkDirection ( ) ;
2012-07-19 12:10:55 +03:00
}
2012-10-03 17:49:29 +03:00
else if ( quest - > missionType = = CQuest : : MISSION_KILL_HERO )
2012-07-19 12:10:55 +03:00
{
2012-10-03 17:49:29 +03:00
quest - > heroName = getHeroToKill ( false ) - > name ;
quest - > heroPortrait = getHeroToKill ( false ) - > portrait ;
2012-07-19 12:10:55 +03:00
}
}
2012-07-08 09:33:41 +03:00
2013-07-23 08:41:42 +03:00
void CGSeerHut : : init ( )
2010-01-01 14:15:20 +02:00
{
2010-01-27 07:11:31 +02:00
seerName = VLC - > generaltexth - > seerNames [ ran ( ) % VLC - > generaltexth - > seerNames . size ( ) ] ;
2013-07-23 08:41:42 +03:00
quest - > textOption = ran ( ) % 3 ;
}
void CGSeerHut : : initObj ( )
{
init ( ) ;
2013-02-02 01:04:25 +03:00
quest - > progress = CQuest : : NOT_ACTIVE ;
2012-10-03 17:49:29 +03:00
if ( quest - > missionType )
2010-02-02 19:05:03 +02:00
{
2012-10-03 17:49:29 +03:00
if ( ! quest - > isCustomFirst )
quest - > firstVisitText = VLC - > generaltexth - > quests [ quest - > missionType - 1 ] [ 0 ] [ quest - > textOption ] ;
if ( ! quest - > isCustomNext )
quest - > nextVisitText = VLC - > generaltexth - > quests [ quest - > missionType - 1 ] [ 1 ] [ quest - > textOption ] ;
if ( ! quest - > isCustomComplete )
quest - > completedText = VLC - > generaltexth - > quests [ quest - > missionType - 1 ] [ 2 ] [ quest - > textOption ] ;
2010-02-02 19:05:03 +02:00
}
else
2013-07-23 18:03:01 +03:00
{
quest - > progress = CQuest : : COMPLETE ;
2012-10-03 17:49:29 +03:00
quest - > firstVisitText = VLC - > generaltexth - > seerEmpty [ quest - > textOption ] ;
2013-07-23 18:03:01 +03:00
}
2010-06-06 12:50:37 +03:00
2010-01-01 14:15:20 +02:00
}
2012-07-08 19:36:20 +03:00
void CGSeerHut : : getRolloverText ( MetaString & text , bool onHover ) const
{
2012-10-03 17:49:29 +03:00
quest - > getRolloverText ( text , onHover ) ; //TODO: simplify?
2012-07-08 19:36:20 +03:00
if ( ! onHover )
text . addReplacement ( seerName ) ;
}
2009-12-30 22:49:10 +02:00
const std : : string & CGSeerHut : : getHoverText ( ) const
{
2010-02-07 18:05:27 +02:00
switch ( ID )
{
2012-09-23 21:01:04 +03:00
case Obj : : SEER_HUT :
2013-02-02 01:04:25 +03:00
if ( quest - > progress ! = CQuest : : NOT_ACTIVE )
2012-09-23 21:01:04 +03:00
{
hoverName = VLC - > generaltexth - > allTexts [ 347 ] ;
boost : : algorithm : : replace_first ( hoverName , " %s " , seerName ) ;
}
else //just seer hut
hoverName = VLC - > generaltexth - > names [ ID ] ;
break ;
case Obj : : QUEST_GUARD :
hoverName = VLC - > generaltexth - > names [ ID ] ;
break ;
default :
2013-04-09 17:31:36 +03:00
logGlobal - > debugStream ( ) < < " unrecognized quest object " ;
2010-02-07 18:05:27 +02:00
}
2012-10-03 17:49:29 +03:00
if ( quest - > progress & quest - > missionType ) //rollover when the quest is active
2010-02-07 18:05:27 +02:00
{
MetaString ms ;
2012-07-19 21:52:44 +03:00
getRolloverText ( ms , true ) ;
2012-07-08 09:33:41 +03:00
hoverName + = ms . toString ( ) ;
}
return hoverName ;
}
void CQuest : : addReplacements ( MetaString & out , const std : : string & base ) const
{
switch ( missionType )
{
case MISSION_KILL_CREATURE :
out . addReplacement ( stackToKill ) ;
if ( std : : count ( base . begin ( ) , base . end ( ) , ' % ' ) = = 2 ) //say where is placed monster
2010-02-07 18:05:27 +02:00
{
2012-07-08 09:33:41 +03:00
out . addReplacement ( VLC - > generaltexth - > arraytxt [ 147 + stackDirection ] ) ;
2010-02-07 18:05:27 +02:00
}
2012-07-08 09:33:41 +03:00
break ;
case MISSION_KILL_HERO :
out . addReplacement ( heroName ) ;
break ;
}
}
2012-09-16 16:34:01 +03:00
bool IQuestObject : : checkQuest ( const CGHeroInstance * h ) const
{
2012-10-03 17:49:29 +03:00
return quest - > checkQuest ( h ) ;
2012-09-16 16:34:01 +03:00
}
void IQuestObject : : getVisitText ( MetaString & text , std : : vector < Component > & components , bool isCustom , bool FirstVisit , const CGHeroInstance * h ) const
{
2012-10-03 17:49:29 +03:00
quest - > getVisitText ( text , components , isCustom , FirstVisit , h ) ;
2012-09-16 16:34:01 +03:00
}
2012-07-08 09:33:41 +03:00
void CGSeerHut : : getCompletionText ( MetaString & text , std : : vector < Component > & components , bool isCustom , const CGHeroInstance * h ) const
{
2012-10-03 17:49:29 +03:00
quest - > getCompletionText ( text , components , isCustom , h ) ;
2012-07-08 09:33:41 +03:00
switch ( rewardType )
{
2013-02-02 01:04:25 +03:00
case EXPERIENCE : components . push_back ( Component ( Component : : EXPERIENCE , 0 , h - > calculateXp ( rVal ) , 0 ) ) ;
2012-07-08 09:33:41 +03:00
break ;
2013-02-02 01:04:25 +03:00
case MANA_POINTS : components . push_back ( Component ( Component : : PRIM_SKILL , 5 , rVal , 0 ) ) ;
2012-07-08 09:33:41 +03:00
break ;
2013-02-02 01:04:25 +03:00
case MORALE_BONUS : components . push_back ( Component ( Component : : MORALE , 0 , rVal , 0 ) ) ;
2012-07-08 09:33:41 +03:00
break ;
2013-02-02 01:04:25 +03:00
case LUCK_BONUS : components . push_back ( Component ( Component : : LUCK , 0 , rVal , 0 ) ) ;
2012-07-08 09:33:41 +03:00
break ;
2013-02-02 01:04:25 +03:00
case RESOURCES : components . push_back ( Component ( Component : : RESOURCE , rID , rVal , 0 ) ) ;
2012-07-08 09:33:41 +03:00
break ;
2013-02-02 01:04:25 +03:00
case PRIMARY_SKILL : components . push_back ( Component ( Component : : PRIM_SKILL , rID , rVal , 0 ) ) ;
2012-07-08 09:33:41 +03:00
break ;
2013-02-02 01:04:25 +03:00
case SECONDARY_SKILL : components . push_back ( Component ( Component : : SEC_SKILL , rID , rVal , 0 ) ) ;
2012-07-08 09:33:41 +03:00
break ;
2013-02-02 01:04:25 +03:00
case ARTIFACT : components . push_back ( Component ( Component : : ARTIFACT , rID , 0 , 0 ) ) ;
2012-07-08 09:33:41 +03:00
break ;
2013-02-02 01:04:25 +03:00
case SPELL : components . push_back ( Component ( Component : : SPELL , rID , 0 , 0 ) ) ;
2012-07-08 09:33:41 +03:00
break ;
2013-02-02 01:04:25 +03:00
case CREATURE : components . push_back ( Component ( Component : : CREATURE , rID , rVal , 0 ) ) ;
2012-07-08 09:33:41 +03:00
break ;
2010-02-07 18:05:27 +02:00
}
2009-12-30 22:49:10 +02:00
}
2010-01-30 22:53:47 +02:00
void CGSeerHut : : setPropertyDer ( ui8 what , ui32 val )
2010-01-01 14:15:20 +02:00
{
2010-01-30 22:53:47 +02:00
switch ( what )
2010-01-01 14:15:20 +02:00
{
2010-01-30 22:53:47 +02:00
case 10 :
2013-02-02 01:04:25 +03:00
quest - > progress = static_cast < CQuest : : Eprogress > ( val ) ;
2010-01-30 22:53:47 +02:00
break ;
2010-01-01 14:15:20 +02:00
}
2010-01-30 22:53:47 +02:00
}
2010-02-02 19:05:03 +02:00
void CGSeerHut : : newTurn ( ) const
{
2013-07-23 18:03:01 +03:00
if ( quest - > lastDay > = 0 & & quest - > lastDay < cb - > getDate ( ) - 1 ) //time is up
2010-02-02 19:05:03 +02:00
{
2013-07-23 18:03:01 +03:00
cb - > setObjProperty ( id , 10 , CQuest : : COMPLETE ) ;
2010-02-02 19:05:03 +02:00
}
2010-01-30 22:53:47 +02:00
2010-02-02 19:05:03 +02:00
}
2010-01-30 22:53:47 +02:00
void CGSeerHut : : onHeroVisit ( const CGHeroInstance * h ) const
{
InfoWindow iw ;
iw . player = h - > getOwner ( ) ;
2013-07-23 18:03:01 +03:00
if ( quest - > progress < CQuest : : COMPLETE )
2010-01-01 14:15:20 +02:00
{
2012-10-03 17:49:29 +03:00
bool firstVisit = ! quest - > progress ;
2011-10-16 22:24:05 +03:00
bool failRequirements = ! checkQuest ( h ) ;
2012-07-06 23:19:54 +03:00
bool isCustom = false ;
2012-07-08 09:33:41 +03:00
2012-07-19 21:52:44 +03:00
if ( firstVisit )
2011-10-16 22:24:05 +03:00
{
2012-10-03 17:49:29 +03:00
isCustom = quest - > isCustomFirst ;
2012-09-16 16:34:01 +03:00
cb - > setObjProperty ( id , 10 , CQuest : : IN_PROGRESS ) ;
2012-07-06 22:12:04 +03:00
AddQuest aq ;
2012-10-03 17:49:29 +03:00
aq . quest = QuestInfo ( quest , this , visitablePos ( ) ) ;
2012-07-06 22:12:04 +03:00
aq . player = h - > tempOwner ;
cb - > sendAndApply ( & aq ) ; //TODO: merge with setObjProperty?
2011-10-16 22:24:05 +03:00
}
else if ( failRequirements )
{
2012-10-03 17:49:29 +03:00
isCustom = quest - > isCustomNext ;
2011-10-16 22:24:05 +03:00
}
if ( firstVisit | | failRequirements )
2010-01-01 14:15:20 +02:00
{
2012-07-08 09:33:41 +03:00
getVisitText ( iw . text , iw . components , isCustom , firstVisit , h ) ;
2010-02-07 18:05:27 +02:00
cb - > showInfoDialog ( & iw ) ;
}
2011-10-16 22:24:05 +03:00
if ( ! failRequirements ) // propose completion, also on first visit
2010-02-07 18:05:27 +02:00
{
BlockingDialog bd ( true , false ) ;
bd . player = h - > getOwner ( ) ;
bd . soundID = soundBase : : QUEST ;
2012-07-19 21:52:44 +03:00
2012-07-08 09:33:41 +03:00
getCompletionText ( bd . text , bd . components , isCustom , h ) ;
2012-07-19 21:52:44 +03:00
2013-04-20 14:34:01 +03:00
cb - > showBlockingDialog ( & bd ) ;
2010-02-07 18:05:27 +02:00
return ;
2010-02-02 19:05:03 +02:00
}
2010-01-01 14:15:20 +02:00
}
2010-01-30 22:53:47 +02:00
else
{
2012-10-03 17:49:29 +03:00
iw . text < < VLC - > generaltexth - > seerEmpty [ quest - > textOption ] ;
2012-09-23 21:01:04 +03:00
if ( ID = = Obj : : SEER_HUT )
2010-02-04 22:34:20 +02:00
iw . text . addReplacement ( seerName ) ;
2010-02-07 18:05:27 +02:00
cb - > showInfoDialog ( & iw ) ;
2010-01-30 22:53:47 +02:00
}
}
2010-02-04 22:34:20 +02:00
int CGSeerHut : : checkDirection ( ) const
{
2011-02-11 14:27:38 +02:00
int3 cord = getCreatureToKill ( ) - > pos ;
2010-02-04 22:34:20 +02:00
if ( ( double ) cord . x / ( double ) cb - > getMapSize ( ) . x < 0.34 ) //north
{
if ( ( double ) cord . y / ( double ) cb - > getMapSize ( ) . y < 0.34 ) //northwest
return 8 ;
else if ( ( double ) cord . y / ( double ) cb - > getMapSize ( ) . y < 0.67 ) //north
return 1 ;
else //northeast
return 2 ;
}
else if ( ( double ) cord . x / ( double ) cb - > getMapSize ( ) . x < 0.67 ) //horizontal
{
if ( ( double ) cord . y / ( double ) cb - > getMapSize ( ) . y < 0.34 ) //west
return 7 ;
else if ( ( double ) cord . y / ( double ) cb - > getMapSize ( ) . y < 0.67 ) //central
return 9 ;
else //east
return 3 ;
}
else //south
{
if ( ( double ) cord . y / ( double ) cb - > getMapSize ( ) . y < 0.34 ) //southwest
return 6 ;
else if ( ( double ) cord . y / ( double ) cb - > getMapSize ( ) . y < 0.67 ) //south
return 5 ;
else //southeast
return 4 ;
}
}
2010-12-06 01:10:02 +02:00
void CGSeerHut : : finishQuest ( const CGHeroInstance * h , ui32 accept ) const
2010-02-02 19:05:03 +02:00
{
if ( accept )
{
2012-10-03 17:49:29 +03:00
switch ( quest - > missionType )
2010-02-02 19:05:03 +02:00
{
case CQuest : : MISSION_ART :
2013-06-29 16:05:48 +03:00
for ( auto & elem : quest - > m5arts )
2010-02-07 18:05:27 +02:00
{
2013-06-29 16:05:48 +03:00
cb - > removeArtifact ( ArtifactLocation ( h , h - > getArtPos ( elem , false ) ) ) ;
2010-02-07 18:05:27 +02:00
}
2010-02-02 19:05:03 +02:00
break ;
case CQuest : : MISSION_ARMY :
2012-10-03 17:49:29 +03:00
cb - > takeCreatures ( h - > id , quest - > m6creatures ) ;
2010-02-02 19:05:03 +02:00
break ;
case CQuest : : MISSION_RESOURCES :
for ( int i = 0 ; i < 7 ; + + i )
{
2013-02-04 22:43:16 +03:00
cb - > giveResource ( h - > getOwner ( ) , static_cast < Res : : ERes > ( i ) , - quest - > m7resources [ i ] ) ;
2010-02-02 19:05:03 +02:00
}
break ;
default :
break ;
}
2013-07-23 18:03:01 +03:00
cb - > setObjProperty ( id , 10 , CQuest : : COMPLETE ) ; //mission complete
completeQuest ( h ) ; //make sure to remove QuestGuard at the very end
2010-02-02 19:05:03 +02:00
}
}
2010-02-04 22:34:20 +02:00
void CGSeerHut : : completeQuest ( const CGHeroInstance * h ) const //reward
2010-01-30 22:53:47 +02:00
{
2010-02-04 22:34:20 +02:00
switch ( rewardType )
{
2013-02-02 01:04:25 +03:00
case EXPERIENCE :
2010-07-26 01:47:59 +03:00
{
2012-09-23 21:01:04 +03:00
TExpType expVal = h - > calculateXp ( rVal ) ;
2013-02-09 00:17:39 +03:00
cb - > changePrimSkill ( h , PrimarySkill : : EXPERIENCE , expVal , false ) ;
2010-02-04 22:34:20 +02:00
break ;
2010-07-26 01:47:59 +03:00
}
2013-02-02 01:04:25 +03:00
case MANA_POINTS :
2010-07-26 01:47:59 +03:00
{
2010-02-04 22:34:20 +02:00
cb - > setManaPoints ( h - > id , h - > mana + rVal ) ;
break ;
2010-07-26 01:47:59 +03:00
}
2013-02-02 01:04:25 +03:00
case MORALE_BONUS : case LUCK_BONUS :
2010-02-04 22:34:20 +02:00
{
2010-05-02 21:20:26 +03:00
Bonus hb ( Bonus : : ONE_WEEK , ( rewardType = = 3 ? Bonus : : MORALE : Bonus : : LUCK ) ,
2013-02-14 02:55:42 +03:00
Bonus : : OBJECT , rVal , h - > id . getNum ( ) , " " , - 1 ) ;
2010-02-04 22:34:20 +02:00
GiveBonus gb ;
2013-02-14 02:55:42 +03:00
gb . id = h - > id . getNum ( ) ;
2010-02-04 22:34:20 +02:00
gb . bonus = hb ;
cb - > giveHeroBonus ( & gb ) ;
}
break ;
2013-02-02 01:04:25 +03:00
case RESOURCES :
2013-02-04 22:43:16 +03:00
cb - > giveResource ( h - > getOwner ( ) , static_cast < Res : : ERes > ( rID ) , rVal ) ;
2010-02-04 22:34:20 +02:00
break ;
2013-02-02 01:04:25 +03:00
case PRIMARY_SKILL :
2013-02-09 00:17:39 +03:00
cb - > changePrimSkill ( h , static_cast < PrimarySkill : : PrimarySkill > ( rID ) , rVal , false ) ;
2010-02-04 22:34:20 +02:00
break ;
2013-02-02 01:04:25 +03:00
case SECONDARY_SKILL :
2013-02-12 22:49:40 +03:00
cb - > changeSecSkill ( h , SecondarySkill ( rID ) , rVal , false ) ;
2010-02-04 22:34:20 +02:00
break ;
2013-02-02 01:04:25 +03:00
case ARTIFACT :
2013-02-07 02:24:43 +03:00
cb - > giveHeroNewArtifact ( h , VLC - > arth - > artifacts [ rID ] , ArtifactPosition : : FIRST_AVAILABLE ) ;
2010-02-04 22:34:20 +02:00
break ;
2013-02-02 01:04:25 +03:00
case SPELL :
2010-02-04 22:34:20 +02:00
{
2013-02-11 02:24:57 +03:00
std : : set < SpellID > spell ;
spell . insert ( SpellID ( rID ) ) ;
2013-02-09 00:17:39 +03:00
cb - > changeSpells ( h , true , spell ) ;
2010-02-04 22:34:20 +02:00
}
break ;
2013-02-02 01:04:25 +03:00
case CREATURE :
2010-12-06 01:10:02 +02:00
{
CCreatureSet creatures ;
2013-02-16 17:03:47 +03:00
creatures . setCreature ( SlotID ( 0 ) , CreatureID ( rID ) , rVal ) ;
2010-12-13 01:44:16 +02:00
cb - > giveCreatures ( this , h , creatures , false ) ;
2010-12-06 01:10:02 +02:00
}
2010-02-04 22:34:20 +02:00
break ;
default :
break ;
}
2010-01-01 14:15:20 +02:00
}
2011-02-11 14:27:38 +02:00
const CGHeroInstance * CGSeerHut : : getHeroToKill ( bool allowNull ) const
{
2012-10-03 17:49:29 +03:00
const CGObjectInstance * o = cb - > getObjByQuestIdentifier ( quest - > m13489val ) ;
2011-02-11 14:27:38 +02:00
if ( allowNull & & ! o )
2013-06-26 14:18:27 +03:00
return nullptr ;
2012-09-23 21:01:04 +03:00
assert ( o & & o - > ID = = Obj : : HERO ) ;
2011-02-11 14:27:38 +02:00
return static_cast < const CGHeroInstance * > ( o ) ;
}
const CGCreature * CGSeerHut : : getCreatureToKill ( bool allowNull ) const
{
2012-10-03 17:49:29 +03:00
const CGObjectInstance * o = cb - > getObjByQuestIdentifier ( quest - > m13489val ) ;
2011-02-11 14:27:38 +02:00
if ( allowNull & & ! o )
2013-06-26 14:18:27 +03:00
return nullptr ;
2012-09-23 21:01:04 +03:00
assert ( o & & o - > ID = = Obj : : MONSTER ) ;
2011-02-11 14:27:38 +02:00
return static_cast < const CGCreature * > ( o ) ;
}
2013-04-20 14:34:01 +03:00
void CGSeerHut : : blockingDialogAnswered ( const CGHeroInstance * hero , ui32 answer ) const
{
finishQuest ( hero , answer ) ;
}
2013-07-23 08:41:42 +03:00
void CGQuestGuard : : init ( )
2010-01-30 22:53:47 +02:00
{
2010-02-04 22:34:20 +02:00
blockVisit = true ;
2013-07-23 08:41:42 +03:00
quest - > textOption = ( ran ( ) % 3 ) + 3 ; //3-5
2010-01-30 22:53:47 +02:00
}
2010-02-04 22:34:20 +02:00
void CGQuestGuard : : completeQuest ( const CGHeroInstance * h ) const
2010-01-30 22:53:47 +02:00
{
2013-02-09 00:17:39 +03:00
cb - > removeObject ( this ) ;
2010-01-30 22:53:47 +02:00
}
2009-01-11 00:08:18 +02:00
void CGWitchHut : : initObj ( )
{
ability = allowedAbilities [ ran ( ) % allowedAbilities . size ( ) ] ;
}
void CGWitchHut : : onHeroVisit ( const CGHeroInstance * h ) const
{
InfoWindow iw ;
2009-04-24 00:09:10 +03:00
iw . soundID = soundBase : : gazebo ;
2009-01-11 00:08:18 +02:00
iw . player = h - > getOwner ( ) ;
2012-03-14 16:02:38 +03:00
if ( ! wasVisited ( h - > tempOwner ) )
2013-03-03 20:06:03 +03:00
cb - > setObjProperty ( id , 10 , h - > tempOwner . getNum ( ) ) ;
2013-01-13 15:40:24 +03:00
ui32 txt_id ;
2013-03-03 20:06:03 +03:00
if ( h - > getSecSkillLevel ( SecondarySkill ( ability ) ) ) //you already know this skill
2009-01-11 00:08:18 +02:00
{
2013-01-13 15:40:24 +03:00
txt_id = 172 ;
2009-01-11 00:08:18 +02:00
}
2012-12-18 14:24:13 +03:00
else if ( ! h - > canLearnSkill ( ) ) //already all skills slots used
2009-01-11 00:08:18 +02:00
{
2013-01-13 15:40:24 +03:00
txt_id = 173 ;
2009-01-11 00:08:18 +02:00
}
else //give sec skill
{
2012-08-31 20:39:11 +03:00
iw . components . push_back ( Component ( Component : : SEC_SKILL , ability , 1 , 0 ) ) ;
2013-01-13 15:40:24 +03:00
txt_id = 171 ;
2013-02-12 22:49:40 +03:00
cb - > changeSecSkill ( h , SecondarySkill ( ability ) , 1 , true ) ;
2009-01-11 00:08:18 +02:00
}
2013-01-13 15:40:24 +03:00
iw . text . addTxt ( MetaString : : ADVOB_TXT , txt_id ) ;
iw . text . addReplacement ( MetaString : : SEC_SKILL_NAME , ability ) ;
2009-01-11 00:08:18 +02:00
cb - > showInfoDialog ( & iw ) ;
2009-02-03 07:28:05 +02:00
}
2009-02-20 14:39:27 +02:00
const std : : string & CGWitchHut : : getHoverText ( ) const
{
hoverName = VLC - > generaltexth - > names [ ID ] ;
2013-01-15 17:20:48 +03:00
if ( wasVisited ( cb - > getLocalPlayer ( ) ) )
2009-02-20 14:39:27 +02:00
{
hoverName + = " \n " + VLC - > generaltexth - > allTexts [ 356 ] ; // + (learn %s)
boost : : algorithm : : replace_first ( hoverName , " %s " , VLC - > generaltexth - > skillName [ ability ] ) ;
2009-07-27 20:55:56 +03:00
const CGHeroInstance * h = cb - > getSelectedHero ( cb - > getCurrentPlayer ( ) ) ;
2013-02-12 22:49:40 +03:00
if ( h & & h - > getSecSkillLevel ( SecondarySkill ( ability ) ) ) //hero knows that ability
2009-02-20 14:39:27 +02:00
hoverName + = " \n \n " + VLC - > generaltexth - > allTexts [ 357 ] ; // (Already learned)
}
return hoverName ;
}
2012-03-14 16:02:38 +03:00
bool CGBonusingObject : : wasVisited ( const CGHeroInstance * h ) const
{
return h - > hasBonusFrom ( Bonus : : OBJECT , ID ) ;
}
2009-02-04 15:40:54 +02:00
void CGBonusingObject : : onHeroVisit ( const CGHeroInstance * h ) const
{
2010-05-02 21:20:26 +03:00
bool visited = h - > hasBonusFrom ( Bonus : : OBJECT , ID ) ;
2012-07-06 23:19:54 +03:00
int messageID = 0 ;
2013-03-14 23:44:00 +03:00
int bonusMove = 0 ;
2013-01-12 16:53:02 +03:00
ui32 descr_id = 0 ;
2009-02-04 15:40:54 +02:00
InfoWindow iw ;
iw . player = h - > tempOwner ;
2009-02-05 11:49:45 +02:00
GiveBonus gbonus ;
2013-02-14 02:55:42 +03:00
gbonus . id = h - > id . getNum ( ) ;
2010-05-02 21:20:26 +03:00
gbonus . bonus . duration = Bonus : : ONE_BATTLE ;
gbonus . bonus . source = Bonus : : OBJECT ;
2011-02-20 20:32:39 +02:00
gbonus . bonus . sid = ID ;
2009-02-04 15:40:54 +02:00
2010-05-02 21:20:26 +03:00
bool second = false ;
Bonus secondBonus ;
2009-02-04 15:40:54 +02:00
switch ( ID )
{
2012-09-23 21:01:04 +03:00
case Obj : : BUOY :
2009-07-19 10:16:33 +03:00
messageID = 21 ;
2013-03-14 23:44:00 +03:00
iw . soundID = soundBase : : MORALE ;
2010-05-02 21:20:26 +03:00
gbonus . bonus . type = Bonus : : MORALE ;
2009-07-19 10:16:33 +03:00
gbonus . bonus . val = + 1 ;
2013-01-12 16:53:02 +03:00
descr_id = 94 ;
2009-07-19 10:16:33 +03:00
break ;
2012-09-23 21:01:04 +03:00
case Obj : : SWAN_POND :
2009-02-04 15:40:54 +02:00
messageID = 29 ;
2013-03-14 23:44:00 +03:00
iw . soundID = soundBase : : LUCK ;
2010-05-02 21:20:26 +03:00
gbonus . bonus . type = Bonus : : LUCK ;
2009-02-05 11:49:45 +02:00
gbonus . bonus . val = 2 ;
2013-01-12 16:53:02 +03:00
descr_id = 67 ;
2009-02-05 11:49:45 +02:00
bonusMove = - h - > movement ;
break ;
2012-09-23 21:01:04 +03:00
case Obj : : FAERIE_RING :
2009-02-04 15:40:54 +02:00
messageID = 49 ;
2013-03-14 23:44:00 +03:00
iw . soundID = soundBase : : LUCK ;
2010-05-02 21:20:26 +03:00
gbonus . bonus . type = Bonus : : LUCK ;
2009-02-05 11:49:45 +02:00
gbonus . bonus . val = 1 ;
2013-01-12 16:53:02 +03:00
descr_id = 71 ;
2009-02-04 15:40:54 +02:00
break ;
2012-09-23 21:01:04 +03:00
case Obj : : FOUNTAIN_OF_FORTUNE :
2009-02-04 15:40:54 +02:00
messageID = 55 ;
2013-03-14 23:44:00 +03:00
iw . soundID = soundBase : : LUCK ;
2010-05-02 21:20:26 +03:00
gbonus . bonus . type = Bonus : : LUCK ;
2009-02-05 11:49:45 +02:00
gbonus . bonus . val = rand ( ) % 5 - 1 ;
2013-01-12 16:53:02 +03:00
descr_id = 69 ;
2009-07-09 22:15:22 +03:00
gbonus . bdescr . addReplacement ( ( gbonus . bonus . val < 0 ? " - " : " + " ) + boost : : lexical_cast < std : : string > ( gbonus . bonus . val ) ) ;
2009-02-04 15:40:54 +02:00
break ;
2012-09-23 21:01:04 +03:00
case Obj : : IDOL_OF_FORTUNE :
2009-02-04 15:40:54 +02:00
messageID = 62 ;
2013-03-14 23:44:00 +03:00
iw . soundID = soundBase : : experience ;
2010-05-02 21:20:26 +03:00
2009-02-05 11:49:45 +02:00
gbonus . bonus . val = 1 ;
2013-01-12 16:53:02 +03:00
descr_id = 68 ;
2013-02-02 11:29:57 +03:00
if ( cb - > getDate ( Date : : DAY_OF_WEEK ) = = 7 ) //7th day of week
2010-05-02 21:20:26 +03:00
{
gbonus . bonus . type = Bonus : : MORALE ;
second = true ;
secondBonus = gbonus . bonus ;
secondBonus . type = Bonus : : LUCK ;
}
else
{
2013-02-02 11:29:57 +03:00
gbonus . bonus . type = ( cb - > getDate ( Date : : DAY_OF_WEEK ) % 2 ) ? Bonus : : LUCK : Bonus : : MORALE ;
2010-05-02 21:20:26 +03:00
}
2009-02-05 11:49:45 +02:00
break ;
2012-09-23 21:01:04 +03:00
case Obj : : MERMAID :
2009-07-19 10:16:33 +03:00
messageID = 83 ;
2013-03-14 23:44:00 +03:00
iw . soundID = soundBase : : LUCK ;
2010-05-02 21:20:26 +03:00
gbonus . bonus . type = Bonus : : LUCK ;
2009-07-19 10:16:33 +03:00
gbonus . bonus . val = 1 ;
2013-01-12 16:53:02 +03:00
descr_id = 72 ;
2009-07-19 10:16:33 +03:00
break ;
2012-09-23 21:01:04 +03:00
case Obj : : RALLY_FLAG :
2013-03-14 23:44:00 +03:00
iw . soundID = soundBase : : MORALE ;
2009-02-05 11:49:45 +02:00
messageID = 111 ;
2010-05-02 21:20:26 +03:00
gbonus . bonus . type = Bonus : : MORALE ;
2009-02-05 11:49:45 +02:00
gbonus . bonus . val = 1 ;
2013-01-12 16:53:02 +03:00
descr_id = 102 ;
2010-05-02 21:20:26 +03:00
second = true ;
secondBonus = gbonus . bonus ;
secondBonus . type = Bonus : : LUCK ;
2009-02-05 11:49:45 +02:00
bonusMove = 400 ;
break ;
2012-09-23 21:01:04 +03:00
case Obj : : OASIS :
2013-03-14 23:44:00 +03:00
iw . soundID = soundBase : : MORALE ;
2009-02-05 11:49:45 +02:00
messageID = 95 ;
2010-05-02 21:20:26 +03:00
gbonus . bonus . type = Bonus : : MORALE ;
2009-02-05 11:49:45 +02:00
gbonus . bonus . val = 1 ;
2013-01-12 16:53:02 +03:00
descr_id = 95 ;
2009-02-05 11:49:45 +02:00
bonusMove = 800 ;
break ;
2012-09-23 21:01:04 +03:00
case Obj : : TEMPLE :
2009-02-05 11:49:45 +02:00
messageID = 140 ;
2009-04-22 21:48:56 +03:00
iw . soundID = soundBase : : temple ;
2010-05-02 21:20:26 +03:00
gbonus . bonus . type = Bonus : : MORALE ;
2013-02-02 11:29:57 +03:00
if ( cb - > getDate ( Date : : DAY_OF_WEEK ) = = 7 ) //sunday
2009-02-05 11:49:45 +02:00
{
gbonus . bonus . val = 2 ;
2013-01-12 16:53:02 +03:00
descr_id = 97 ;
2009-02-05 11:49:45 +02:00
}
else
{
gbonus . bonus . val = 1 ;
2013-01-12 16:53:02 +03:00
descr_id = 96 ;
2009-02-05 11:49:45 +02:00
}
break ;
2012-09-23 21:01:04 +03:00
case Obj : : WATERING_HOLE :
2013-03-14 23:44:00 +03:00
iw . soundID = soundBase : : MORALE ;
2009-02-05 11:49:45 +02:00
messageID = 166 ;
2010-05-02 21:20:26 +03:00
gbonus . bonus . type = Bonus : : MORALE ;
2009-02-05 11:49:45 +02:00
gbonus . bonus . val = 1 ;
2013-01-12 16:53:02 +03:00
descr_id = 100 ;
2009-02-05 11:49:45 +02:00
bonusMove = 400 ;
break ;
2012-09-23 21:01:04 +03:00
case Obj : : FOUNTAIN_OF_YOUTH :
2013-03-14 23:44:00 +03:00
iw . soundID = soundBase : : MORALE ;
2009-02-05 11:49:45 +02:00
messageID = 57 ;
2010-05-02 21:20:26 +03:00
gbonus . bonus . type = Bonus : : MORALE ;
2009-02-05 11:49:45 +02:00
gbonus . bonus . val = 1 ;
2013-01-12 16:53:02 +03:00
descr_id = 103 ;
2009-02-05 11:49:45 +02:00
bonusMove = 400 ;
2009-02-04 15:40:54 +02:00
break ;
2012-09-23 21:01:04 +03:00
case Obj : : STABLES :
2013-03-14 23:44:00 +03:00
iw . soundID = soundBase : : STORE ;
2011-09-02 08:44:53 +03:00
bool someUpgradeDone = false ;
2013-06-29 16:05:48 +03:00
for ( auto i = h - > Slots ( ) . begin ( ) ; i ! = h - > Slots ( ) . end ( ) ; + + i )
2009-08-15 19:12:30 +03:00
{
2013-02-07 20:34:50 +03:00
if ( i - > second - > type - > idNumber = = CreatureID : : CAVALIER )
2011-09-02 08:44:53 +03:00
{
2013-02-07 20:34:50 +03:00
cb - > changeStackType ( StackLocation ( h , i - > first ) , VLC - > creh - > creatures [ CreatureID : : CHAMPION ] ) ;
2011-09-02 08:44:53 +03:00
someUpgradeDone = true ;
}
2009-08-15 19:12:30 +03:00
}
2011-09-02 08:44:53 +03:00
if ( someUpgradeDone )
2009-08-15 19:12:30 +03:00
{
2010-07-07 15:20:15 +03:00
messageID = 138 ;
2010-08-17 18:50:17 +03:00
iw . components . push_back ( Component ( Component : : CREATURE , 11 , 0 , 1 ) ) ;
2009-08-15 19:12:30 +03:00
}
2010-07-07 15:20:15 +03:00
else
messageID = 137 ;
2011-09-02 08:44:53 +03:00
2010-05-02 21:20:26 +03:00
gbonus . bonus . type = Bonus : : LAND_MOVEMENT ;
2009-08-11 10:50:29 +03:00
gbonus . bonus . val = 600 ;
2010-02-14 08:53:37 +02:00
bonusMove = 600 ;
2010-05-02 21:20:26 +03:00
gbonus . bonus . duration = Bonus : : ONE_WEEK ;
2013-01-12 16:53:02 +03:00
//gbonus.bdescr << std::pair<ui8,ui32>(6, 100);
2009-08-11 10:50:29 +03:00
break ;
2009-02-04 15:40:54 +02:00
}
2013-01-12 16:53:02 +03:00
if ( descr_id ! = 0 )
gbonus . bdescr . addTxt ( MetaString : : ARRAY_TXT , descr_id ) ;
2012-07-06 23:19:54 +03:00
assert ( messageID ) ;
2009-02-04 15:40:54 +02:00
if ( visited )
{
2012-09-23 21:01:04 +03:00
if ( ID = = Obj : : RALLY_FLAG | | ID = = Obj : : OASIS | | ID = = Obj : : MERMAID | | ID = = Obj : : STABLES )
2009-02-05 11:49:45 +02:00
messageID - - ;
else
messageID + + ;
2009-02-04 15:40:54 +02:00
}
else
{
2010-05-02 21:20:26 +03:00
//TODO: fix if second bonus val != main bonus val
if ( gbonus . bonus . type = = Bonus : : MORALE | | secondBonus . type = = Bonus : : MORALE )
2012-08-31 20:39:11 +03:00
iw . components . push_back ( Component ( Component : : MORALE , 0 , gbonus . bonus . val , 0 ) ) ;
2010-05-02 21:20:26 +03:00
if ( gbonus . bonus . type = = Bonus : : LUCK | | secondBonus . type = = Bonus : : LUCK )
2012-08-31 20:39:11 +03:00
iw . components . push_back ( Component ( Component : : LUCK , 0 , gbonus . bonus . val , 0 ) ) ;
2009-02-04 15:40:54 +02:00
cb - > giveHeroBonus ( & gbonus ) ;
2010-05-02 21:20:26 +03:00
if ( second )
{
gbonus . bonus = secondBonus ;
cb - > giveHeroBonus ( & gbonus ) ;
}
2010-02-14 08:53:37 +02:00
if ( bonusMove ) //swan pond - take all move points, stables - give move point this day
2009-02-04 15:40:54 +02:00
{
SetMovePoints smp ;
smp . hid = h - > id ;
2009-02-05 11:49:45 +02:00
smp . val = h - > movement + bonusMove ;
2009-02-04 15:40:54 +02:00
cb - > setMovePoints ( & smp ) ;
}
}
2013-01-12 13:32:03 +03:00
iw . text . addTxt ( MetaString : : ADVOB_TXT , messageID ) ;
2009-02-04 15:40:54 +02:00
cb - > showInfoDialog ( & iw ) ;
}
const std : : string & CGBonusingObject : : getHoverText ( ) const
2009-02-06 13:15:39 +02:00
{
const CGHeroInstance * h = cb - > getSelectedHero ( cb - > getCurrentPlayer ( ) ) ;
hoverName = VLC - > generaltexth - > names [ ID ] ;
2012-07-19 21:52:44 +03:00
if ( h )
2009-02-06 13:15:39 +02:00
{
2013-01-13 15:40:24 +03:00
bool visited = h - > hasBonusFrom ( Bonus : : OBJECT , ID ) ;
hoverName + = " " + visitedTxt ( visited ) ;
2009-02-06 13:15:39 +02:00
}
return hoverName ;
}
2009-07-19 10:16:33 +03:00
void CGBonusingObject : : initObj ( )
{
2012-09-23 21:01:04 +03:00
if ( ID = = Obj : : BUOY | | ID = = Obj : : MERMAID )
2009-07-19 10:16:33 +03:00
{
blockVisit = true ;
}
}
2012-07-19 21:52:44 +03:00
void CGMagicSpring : : onHeroVisit ( const CGHeroInstance * h ) const
{
int messageID ;
2013-01-12 13:32:03 +03:00
2012-07-19 21:52:44 +03:00
if ( ! visited )
{
if ( h - > mana > h - > manaLimit ( ) )
messageID = 76 ;
else
{
messageID = 74 ;
cb - > setManaPoints ( h - > id , 2 * h - > manaLimit ( ) ) ;
cb - > setObjProperty ( id , ObjProperty : : VISITED , true ) ;
}
}
else
messageID = 75 ;
2013-01-12 13:32:03 +03:00
showInfoDialog ( h , messageID , soundBase : : GENIE ) ;
2012-07-19 21:52:44 +03:00
}
const std : : string & CGMagicSpring : : getHoverText ( ) const
{
2013-01-13 15:40:24 +03:00
hoverName = VLC - > generaltexth - > names [ ID ] + " " + visitedTxt ( visited ) ;
2009-09-23 15:42:14 +03:00
return hoverName ;
2012-07-19 21:52:44 +03:00
}
2009-09-23 15:42:14 +03:00
2009-02-06 13:15:39 +02:00
void CGMagicWell : : onHeroVisit ( const CGHeroInstance * h ) const
{
int message ;
2013-01-12 13:32:03 +03:00
2010-05-02 21:20:26 +03:00
if ( h - > hasBonusFrom ( Bonus : : OBJECT , ID ) ) //has already visited Well today
2009-02-06 13:15:39 +02:00
{
2013-01-12 13:32:03 +03:00
message = 78 ; //"A second drink at the well in one day will not help you."
2009-02-06 13:15:39 +02:00
}
else if ( h - > mana < h - > manaLimit ( ) )
{
2009-07-19 10:16:33 +03:00
giveDummyBonus ( h - > id ) ;
2009-02-06 13:15:39 +02:00
cb - > setManaPoints ( h - > id , h - > manaLimit ( ) ) ;
message = 77 ;
}
else
{
message = 79 ;
}
2013-01-12 13:32:03 +03:00
showInfoDialog ( h , message , soundBase : : faerie ) ;
2009-02-06 13:15:39 +02:00
}
const std : : string & CGMagicWell : : getHoverText ( ) const
2009-02-04 15:40:54 +02:00
{
2009-07-19 10:16:33 +03:00
getNameVis ( hoverName ) ;
2009-02-04 15:40:54 +02:00
return hoverName ;
2009-02-08 08:42:15 +02:00
}
2009-08-16 18:39:18 +03:00
void CGPandoraBox : : initObj ( )
{
2012-09-23 21:01:04 +03:00
blockVisit = ( ID = = Obj : : PANDORAS_BOX ) ; //block only if it's really pandora's box (events also derive from that class)
2013-05-28 00:46:04 +03:00
hasGuardians = stacks . size ( ) ;
2009-08-16 18:39:18 +03:00
}
2009-08-17 13:47:08 +03:00
2009-08-16 18:39:18 +03:00
void CGPandoraBox : : onHeroVisit ( const CGHeroInstance * h ) const
{
BlockingDialog bd ( true , false ) ;
bd . player = h - > getOwner ( ) ;
bd . soundID = soundBase : : QUEST ;
bd . text . addTxt ( MetaString : : ADVOB_TXT , 14 ) ;
2013-04-20 14:34:01 +03:00
cb - > showBlockingDialog ( & bd ) ;
2009-08-19 09:56:53 +03:00
}
2013-05-28 00:46:04 +03:00
void CGPandoraBox : : giveContentsUpToExp ( const CGHeroInstance * h ) const
2009-02-08 08:42:15 +02:00
{
2013-05-28 00:46:04 +03:00
cb - > removeAfterVisit ( this ) ;
2009-02-08 08:42:15 +02:00
InfoWindow iw ;
2009-04-21 01:57:07 +03:00
iw . player = h - > getOwner ( ) ;
bool changesPrimSkill = false ;
2013-06-29 16:05:48 +03:00
for ( auto & elem : primskills )
2009-04-21 01:57:07 +03:00
{
2013-06-29 16:05:48 +03:00
if ( elem )
2009-04-21 01:57:07 +03:00
{
changesPrimSkill = true ;
break ;
}
}
if ( gainedExp | | changesPrimSkill | | abilities . size ( ) )
{
2012-09-23 21:01:04 +03:00
TExpType expVal = h - > calculateXp ( gainedExp ) ;
2011-06-25 12:28:28 +03:00
//getText(iw,afterBattle,175,h); //wtf?
iw . text . addTxt ( MetaString : : ADVOB_TXT , 175 ) ; //%s learns something
iw . text . addReplacement ( h - > name ) ;
2009-04-21 01:57:07 +03:00
2010-07-26 01:47:59 +03:00
if ( expVal )
iw . components . push_back ( Component ( Component : : EXPERIENCE , 0 , expVal , 0 ) ) ;
2009-04-21 01:57:07 +03:00
for ( int i = 0 ; i < primskills . size ( ) ; i + + )
if ( primskills [ i ] )
iw . components . push_back ( Component ( Component : : PRIM_SKILL , i , primskills [ i ] , 0 ) ) ;
for ( int i = 0 ; i < abilities . size ( ) ; i + + )
iw . components . push_back ( Component ( Component : : SEC_SKILL , abilities [ i ] , abilityLevels [ i ] , 0 ) ) ;
cb - > showInfoDialog ( & iw ) ;
//give sec skills
for ( int i = 0 ; i < abilities . size ( ) ; i + + )
{
2013-02-04 22:43:16 +03:00
int curLev = h - > getSecSkillLevel ( abilities [ i ] ) ;
2009-04-21 01:57:07 +03:00
2012-12-18 14:24:13 +03:00
if ( ( curLev & & curLev < abilityLevels [ i ] ) | | ( h - > canLearnSkill ( ) ) )
2009-04-21 01:57:07 +03:00
{
2013-02-09 01:42:46 +03:00
cb - > changeSecSkill ( h , abilities [ i ] , abilityLevels [ i ] , true ) ;
2009-04-21 01:57:07 +03:00
}
}
2013-05-28 00:46:04 +03:00
//give prim skills
for ( int i = 0 ; i < primskills . size ( ) ; i + + )
if ( primskills [ i ] )
cb - > changePrimSkill ( h , static_cast < PrimarySkill : : PrimarySkill > ( i ) , primskills [ i ] , false ) ;
assert ( ! cb - > isVisitCoveredByAnotherQuery ( this , h ) ) ;
//give exp
if ( expVal )
cb - > changePrimSkill ( h , PrimarySkill : : EXPERIENCE , expVal , false ) ;
2009-04-21 01:57:07 +03:00
}
2013-05-28 00:46:04 +03:00
if ( ! cb - > isVisitCoveredByAnotherQuery ( this , h ) )
giveContentsAfterExp ( h ) ;
//Otherwise continuation occurs via post-level-up callback.
}
void CGPandoraBox : : giveContentsAfterExp ( const CGHeroInstance * h ) const
{
bool hadGuardians = hasGuardians ; //copy, because flag will be emptied after issuing first post-battle message
std : : string msg = message ; //in case box is removed in the meantime
InfoWindow iw ;
iw . player = h - > getOwner ( ) ;
2009-04-23 18:48:53 +03:00
if ( spells . size ( ) )
{
2013-02-11 02:24:57 +03:00
std : : set < SpellID > spellsToGive ;
2009-04-23 18:48:53 +03:00
iw . components . clear ( ) ;
2011-06-25 12:28:28 +03:00
if ( spells . size ( ) > 1 )
{
iw . text . addTxt ( MetaString : : ADVOB_TXT , 188 ) ; //%s learns spells
}
else
{
iw . text . addTxt ( MetaString : : ADVOB_TXT , 184 ) ; //%s learns a spell
}
iw . text . addReplacement ( h - > name ) ;
2010-12-19 16:39:56 +02:00
std : : vector < ConstTransitivePtr < CSpell > > * sp = & VLC - > spellh - > spells ;
2013-02-11 02:24:57 +03:00
for ( auto i = spells . cbegin ( ) ; i ! = spells . cend ( ) ; i + + )
2009-04-23 18:48:53 +03:00
{
2013-02-04 22:43:16 +03:00
if ( ( * sp ) [ * i ] - > level < = h - > getSecSkillLevel ( SecondarySkill : : WISDOM ) + 2 ) //enough wisdom
2010-09-26 19:11:50 +03:00
{
iw . components . push_back ( Component ( Component : : SPELL , * i , 0 , 0 ) ) ;
spellsToGive . insert ( * i ) ;
}
2009-04-23 18:48:53 +03:00
}
if ( spellsToGive . size ( ) )
{
2013-02-09 00:17:39 +03:00
cb - > changeSpells ( h , true , spellsToGive ) ;
2009-04-23 18:48:53 +03:00
cb - > showInfoDialog ( & iw ) ;
}
}
2009-04-21 01:57:07 +03:00
if ( manaDiff )
{
2013-05-28 00:46:04 +03:00
getText ( iw , hadGuardians , manaDiff , 176 , 177 , h ) ;
2009-04-21 01:57:07 +03:00
iw . components . push_back ( Component ( Component : : PRIM_SKILL , 5 , manaDiff , 0 ) ) ;
cb - > showInfoDialog ( & iw ) ;
cb - > setManaPoints ( h - > id , h - > mana + manaDiff ) ;
}
if ( moraleDiff )
{
2013-05-28 00:46:04 +03:00
getText ( iw , hadGuardians , moraleDiff , 178 , 179 , h ) ;
2009-04-21 01:57:07 +03:00
iw . components . push_back ( Component ( Component : : MORALE , 0 , moraleDiff , 0 ) ) ;
cb - > showInfoDialog ( & iw ) ;
GiveBonus gb ;
2013-02-14 02:55:42 +03:00
gb . bonus = Bonus ( Bonus : : ONE_BATTLE , Bonus : : MORALE , Bonus : : OBJECT , moraleDiff , id . getNum ( ) , " " ) ;
gb . id = h - > id . getNum ( ) ;
2009-04-21 01:57:07 +03:00
cb - > giveHeroBonus ( & gb ) ;
}
if ( luckDiff )
{
2013-05-28 00:46:04 +03:00
getText ( iw , hadGuardians , luckDiff , 180 , 181 , h ) ;
2009-04-21 01:57:07 +03:00
iw . components . push_back ( Component ( Component : : LUCK , 0 , luckDiff , 0 ) ) ;
cb - > showInfoDialog ( & iw ) ;
GiveBonus gb ;
2013-02-14 02:55:42 +03:00
gb . bonus = Bonus ( Bonus : : ONE_BATTLE , Bonus : : LUCK , Bonus : : OBJECT , luckDiff , id . getNum ( ) , " " ) ;
gb . id = h - > id . getNum ( ) ;
2009-04-21 01:57:07 +03:00
cb - > giveHeroBonus ( & gb ) ;
}
iw . components . clear ( ) ;
iw . text . clear ( ) ;
for ( int i = 0 ; i < resources . size ( ) ; i + + )
{
if ( resources [ i ] < 0 )
iw . components . push_back ( Component ( Component : : RESOURCE , i , resources [ i ] , 0 ) ) ;
}
if ( iw . components . size ( ) )
{
2013-05-28 00:46:04 +03:00
getText ( iw , hadGuardians , 182 , h ) ;
2009-04-21 01:57:07 +03:00
cb - > showInfoDialog ( & iw ) ;
}
iw . components . clear ( ) ;
iw . text . clear ( ) ;
for ( int i = 0 ; i < resources . size ( ) ; i + + )
{
if ( resources [ i ] > 0 )
iw . components . push_back ( Component ( Component : : RESOURCE , i , resources [ i ] , 0 ) ) ;
}
if ( iw . components . size ( ) )
{
2013-05-28 00:46:04 +03:00
getText ( iw , hadGuardians , 183 , h ) ;
2009-04-21 01:57:07 +03:00
cb - > showInfoDialog ( & iw ) ;
}
2013-05-28 00:46:04 +03:00
iw . components . clear ( ) ;
// getText(iw,afterBattle,183,h);
2011-06-25 12:28:28 +03:00
iw . text . addTxt ( MetaString : : ADVOB_TXT , 183 ) ; //% has found treasure
iw . text . addReplacement ( h - > name ) ;
2013-06-29 16:05:48 +03:00
for ( auto & elem : artifacts )
2009-04-21 01:57:07 +03:00
{
2013-06-29 16:05:48 +03:00
iw . components . push_back ( Component ( Component : : ARTIFACT , elem , 0 , 0 ) ) ;
2009-07-16 01:46:00 +03:00
if ( iw . components . size ( ) > = 14 )
{
cb - > showInfoDialog ( & iw ) ;
iw . components . clear ( ) ;
2011-06-25 12:28:28 +03:00
iw . text . addTxt ( MetaString : : ADVOB_TXT , 183 ) ; //% has found treasure - once more?
iw . text . addReplacement ( h - > name ) ;
2009-07-16 01:46:00 +03:00
}
2009-04-21 01:57:07 +03:00
}
if ( iw . components . size ( ) )
{
cb - > showInfoDialog ( & iw ) ;
}
for ( int i = 0 ; i < resources . size ( ) ; i + + )
if ( resources [ i ] )
2013-02-04 22:43:16 +03:00
cb - > giveResource ( h - > getOwner ( ) , static_cast < Res : : ERes > ( i ) , resources [ i ] ) ;
2009-04-21 01:57:07 +03:00
2013-06-29 16:05:48 +03:00
for ( auto & elem : artifacts )
cb - > giveHeroNewArtifact ( h , VLC - > arth - > artifacts [ elem ] , ArtifactPosition : : FIRST_AVAILABLE ) ;
2009-04-21 01:57:07 +03:00
iw . components . clear ( ) ;
iw . text . clear ( ) ;
2009-09-23 15:05:33 +03:00
2010-05-02 21:20:26 +03:00
if ( creatures . Slots ( ) . size ( ) )
2009-09-26 12:16:59 +03:00
{ //this part is taken straight from creature bank
2012-07-19 21:52:44 +03:00
MetaString loot ;
2013-06-29 16:05:48 +03:00
for ( auto & elem : creatures . Slots ( ) )
2009-09-26 12:16:59 +03:00
{ //build list of joined creatures
2013-06-29 16:05:48 +03:00
iw . components . push_back ( Component ( * elem . second ) ) ;
2009-09-26 12:16:59 +03:00
loot < < " %s " ;
2013-06-29 16:05:48 +03:00
loot . addReplacement ( * elem . second ) ;
2009-09-25 18:40:28 +03:00
}
2009-09-23 15:05:33 +03:00
2010-12-12 01:11:26 +02:00
if ( creatures . Slots ( ) . size ( ) = = 1 & & creatures . Slots ( ) . begin ( ) - > second - > count = = 1 )
iw . text . addTxt ( MetaString : : ADVOB_TXT , 185 ) ;
2009-09-26 12:16:59 +03:00
else
2010-12-12 01:11:26 +02:00
iw . text . addTxt ( MetaString : : ADVOB_TXT , 186 ) ;
2009-09-26 12:16:59 +03:00
2010-11-22 02:34:46 +02:00
iw . text . addReplacement ( loot . buildList ( ) ) ;
iw . text . addReplacement ( h - > name ) ;
2009-09-26 12:16:59 +03:00
cb - > showInfoDialog ( & iw ) ;
2010-12-13 01:44:16 +02:00
cb - > giveCreatures ( this , h , creatures , true ) ;
2009-09-23 15:05:33 +03:00
}
2013-05-28 00:46:04 +03:00
if ( ! hasGuardians & & msg . size ( ) )
2009-04-21 01:57:07 +03:00
{
2011-03-08 15:27:32 +02:00
iw . text < < msg ;
2009-04-21 01:57:07 +03:00
cb - > showInfoDialog ( & iw ) ;
}
}
2009-08-16 18:39:18 +03:00
void CGPandoraBox : : getText ( InfoWindow & iw , bool & afterBattle , int text , const CGHeroInstance * h ) const
2009-04-21 01:57:07 +03:00
{
2009-07-16 01:46:00 +03:00
if ( afterBattle | | ! message . size ( ) )
2009-04-21 01:57:07 +03:00
{
iw . text . addTxt ( MetaString : : ADVOB_TXT , text ) ; //%s has lost treasure.
2009-07-09 22:15:22 +03:00
iw . text . addReplacement ( h - > name ) ;
2009-04-21 01:57:07 +03:00
}
else
{
iw . text < < message ;
afterBattle = true ;
}
}
2009-08-16 18:39:18 +03:00
void CGPandoraBox : : getText ( InfoWindow & iw , bool & afterBattle , int val , int negative , int positive , const CGHeroInstance * h ) const
2009-04-21 01:57:07 +03:00
{
iw . components . clear ( ) ;
iw . text . clear ( ) ;
2009-07-16 01:46:00 +03:00
if ( afterBattle | | ! message . size ( ) )
2009-04-21 01:57:07 +03:00
{
iw . text . addTxt ( MetaString : : ADVOB_TXT , val < 0 ? negative : positive ) ; //%s's luck takes a turn for the worse / %s's luck increases
2009-07-09 22:15:22 +03:00
iw . text . addReplacement ( h - > name ) ;
2009-04-21 01:57:07 +03:00
}
else
{
iw . text < < message ;
afterBattle = true ;
}
2009-03-14 13:25:25 +02:00
}
2013-04-20 14:34:01 +03:00
void CGPandoraBox : : battleFinished ( const CGHeroInstance * hero , const BattleResult & result ) const
{
if ( result . winner )
return ;
2013-05-28 00:46:04 +03:00
giveContentsUpToExp ( hero ) ;
2013-04-20 14:34:01 +03:00
}
void CGPandoraBox : : blockingDialogAnswered ( const CGHeroInstance * hero , ui32 answer ) const
{
if ( answer )
{
if ( stacksCount ( ) > 0 ) //if pandora's box is protected by army
{
showInfoDialog ( hero , 16 , 0 ) ;
cb - > startBattleI ( hero , this ) ; //grants things after battle
}
else if ( message . size ( ) = = 0 & & resources . size ( ) = = 0
& & primskills . size ( ) = = 0 & & abilities . size ( ) = = 0
& & abilityLevels . size ( ) = = 0 & & artifacts . size ( ) = = 0
& & spells . size ( ) = = 0 & & creatures . Slots ( ) . size ( ) > 0
& & gainedExp = = 0 & & manaDiff = = 0 & & moraleDiff = = 0 & & luckDiff = = 0 ) //if it gives nothing without battle
{
showInfoDialog ( hero , 15 , 0 ) ;
cb - > removeObject ( this ) ;
}
else //if it gives something without battle
{
2013-05-28 00:46:04 +03:00
giveContentsUpToExp ( hero ) ;
2013-04-20 14:34:01 +03:00
}
}
}
2013-05-28 00:46:04 +03:00
void CGPandoraBox : : heroLevelUpDone ( const CGHeroInstance * hero ) const
{
giveContentsAfterExp ( hero ) ;
}
2009-08-19 09:56:53 +03:00
void CGEvent : : onHeroVisit ( const CGHeroInstance * h ) const
{
2013-03-03 20:06:03 +03:00
if ( ! ( availableFor & ( 1 < < h - > tempOwner . getNum ( ) ) ) )
2009-08-19 09:56:53 +03:00
return ;
2012-12-02 15:21:44 +03:00
if ( cb - > getPlayerSettings ( h - > tempOwner ) - > playerID )
2009-08-19 09:56:53 +03:00
{
if ( humanActivate )
activated ( h ) ;
}
else if ( computerActivate )
activated ( h ) ;
}
void CGEvent : : activated ( const CGHeroInstance * h ) const
{
2010-05-02 21:20:26 +03:00
if ( stacksCount ( ) > 0 )
2009-08-19 09:56:53 +03:00
{
InfoWindow iw ;
iw . player = h - > tempOwner ;
if ( message . size ( ) )
iw . text < < message ;
else
iw . text . addTxt ( MetaString : : ADVOB_TXT , 16 ) ;
cb - > showInfoDialog ( & iw ) ;
2013-04-20 14:34:01 +03:00
cb - > startBattleI ( h , this ) ;
2009-08-19 09:56:53 +03:00
}
else
{
2013-05-28 00:46:04 +03:00
giveContentsUpToExp ( h ) ;
2009-08-19 09:56:53 +03:00
}
}
2009-03-14 13:25:25 +02:00
void CGObservatory : : onHeroVisit ( const CGHeroInstance * h ) const
{
2009-04-15 02:29:26 +03:00
InfoWindow iw ;
iw . player = h - > tempOwner ;
2010-06-06 09:05:39 +03:00
switch ( ID )
{
2012-09-23 21:01:04 +03:00
case Obj : : REDWOOD_OBSERVATORY :
case Obj : : PILLAR_OF_FIRE :
{
iw . soundID = soundBase : : LIGHTHOUSE ;
iw . text . addTxt ( MetaString : : ADVOB_TXT , 98 + ( ID = = Obj : : PILLAR_OF_FIRE ) ) ;
2010-06-06 09:05:39 +03:00
2012-09-23 21:01:04 +03:00
FoWChange fw ;
fw . player = h - > tempOwner ;
fw . mode = 1 ;
cb - > getTilesInRange ( fw . tiles , pos , 20 , h - > tempOwner , 1 ) ;
cb - > sendAndApply ( & fw ) ;
break ;
}
case Obj : : COVER_OF_DARKNESS :
{
iw . text . addTxt ( MetaString : : ADVOB_TXT , 31 ) ;
hideTiles ( h - > tempOwner , 20 ) ;
break ;
}
2010-06-06 09:05:39 +03:00
}
2009-04-15 02:29:26 +03:00
cb - > showInfoDialog ( & iw ) ;
2009-03-14 13:25:25 +02:00
}
void CGShrine : : onHeroVisit ( const CGHeroInstance * h ) const
{
2013-02-13 22:35:43 +03:00
if ( spell = = SpellID : : NONE )
2009-03-14 13:25:25 +02:00
{
2013-04-09 17:31:36 +03:00
logGlobal - > errorStream ( ) < < " Not initialized shrine visited! " ;
2009-03-14 13:25:25 +02:00
return ;
}
2012-03-14 16:02:38 +03:00
if ( ! wasVisited ( h - > tempOwner ) )
2013-03-03 20:06:03 +03:00
cb - > setObjProperty ( id , 10 , h - > tempOwner . getNum ( ) ) ;
2009-03-14 19:19:53 +02:00
2009-03-14 13:25:25 +02:00
InfoWindow iw ;
2009-04-24 00:09:10 +03:00
iw . soundID = soundBase : : temple ;
2009-03-14 13:25:25 +02:00
iw . player = h - > getOwner ( ) ;
iw . text . addTxt ( MetaString : : ADVOB_TXT , 127 + ID - 88 ) ;
iw . text . addTxt ( MetaString : : SPELL_NAME , spell ) ;
iw . text < < " . " ;
2012-09-25 17:40:39 +03:00
if ( ! h - > getArt ( ArtifactPosition : : SPELLBOOK ) )
2009-03-14 13:25:25 +02:00
{
iw . text . addTxt ( MetaString : : ADVOB_TXT , 131 ) ;
}
2013-02-04 22:43:16 +03:00
else if ( ID = = Obj : : SHRINE_OF_MAGIC_THOUGHT & & ! h - > getSecSkillLevel ( SecondarySkill : : WISDOM ) ) //it's third level spell and hero doesn't have wisdom
2009-03-14 13:25:25 +02:00
{
iw . text . addTxt ( MetaString : : ADVOB_TXT , 130 ) ;
}
else if ( vstd : : contains ( h - > spells , spell ) ) //hero already knows the spell
{
iw . text . addTxt ( MetaString : : ADVOB_TXT , 174 ) ;
}
else //give spell
{
2013-02-11 02:24:57 +03:00
std : : set < SpellID > spells ;
2013-02-13 22:35:43 +03:00
spells . insert ( spell ) ;
2013-02-09 00:17:39 +03:00
cb - > changeSpells ( h , true , spells ) ;
2009-03-14 13:25:25 +02:00
iw . components . push_back ( Component ( Component : : SPELL , spell , 0 , 0 ) ) ;
}
cb - > showInfoDialog ( & iw ) ;
}
void CGShrine : : initObj ( )
{
2013-02-13 22:35:43 +03:00
if ( spell = = SpellID : : NONE ) //spell not set
2009-03-14 13:25:25 +02:00
{
int level = ID - 87 ;
2013-02-11 02:24:57 +03:00
std : : vector < SpellID > possibilities ;
2009-09-24 22:28:26 +03:00
cb - > getAllowedSpells ( possibilities , level ) ;
2009-03-14 13:25:25 +02:00
if ( ! possibilities . size ( ) )
{
2013-04-09 17:31:36 +03:00
logGlobal - > errorStream ( ) < < " Error: cannot init shrine, no allowed spells! " ;
2009-03-14 13:25:25 +02:00
return ;
}
spell = possibilities [ ran ( ) % possibilities . size ( ) ] ;
}
}
const std : : string & CGShrine : : getHoverText ( ) const
{
2009-03-14 19:19:53 +02:00
hoverName = VLC - > generaltexth - > names [ ID ] ;
2012-03-14 16:02:38 +03:00
if ( wasVisited ( cb - > getCurrentPlayer ( ) ) ) //TODO: use local player, not current
2009-03-14 19:19:53 +02:00
{
hoverName + = " \n " + VLC - > generaltexth - > allTexts [ 355 ] ; // + (learn %s)
2013-02-13 22:35:43 +03:00
boost : : algorithm : : replace_first ( hoverName , " %s " , spell . toSpell ( ) - > name ) ;
2009-03-14 19:19:53 +02:00
const CGHeroInstance * h = cb - > getSelectedHero ( cb - > getCurrentPlayer ( ) ) ;
if ( h & & vstd : : contains ( h - > spells , spell ) ) //hero knows that ability
hoverName + = " \n \n " + VLC - > generaltexth - > allTexts [ 354 ] ; // (Already learned)
}
2009-03-14 13:25:25 +02:00
return hoverName ;
2009-03-14 19:19:53 +02:00
}
2009-03-19 16:17:19 +02:00
void CGSignBottle : : initObj ( )
{
//if no text is set than we pick random from the predefined ones
if ( ! message . size ( ) )
message = VLC - > generaltexth - > randsign [ ran ( ) % VLC - > generaltexth - > randsign . size ( ) ] ;
2009-07-19 10:16:33 +03:00
2012-09-23 21:01:04 +03:00
if ( ID = = Obj : : OCEAN_BOTTLE )
2009-07-19 10:16:33 +03:00
{
blockVisit = true ;
}
2009-03-19 16:17:19 +02:00
}
void CGSignBottle : : onHeroVisit ( const CGHeroInstance * h ) const
{
InfoWindow iw ;
2009-04-24 00:09:10 +03:00
iw . soundID = soundBase : : STORE ;
2009-03-19 16:17:19 +02:00
iw . player = h - > getOwner ( ) ;
iw . text < < message ;
cb - > showInfoDialog ( & iw ) ;
2009-07-20 01:16:07 +03:00
2012-09-23 21:01:04 +03:00
if ( ID = = Obj : : OCEAN_BOTTLE )
2013-02-09 00:17:39 +03:00
cb - > removeObject ( this ) ;
2009-04-08 22:55:50 +03:00
}
2013-01-13 15:40:24 +03:00
//TODO: remove
//void CGScholar::giveAnyBonus( const CGHeroInstance * h ) const
//{
//
//}
2009-04-08 22:55:50 +03:00
void CGScholar : : onHeroVisit ( const CGHeroInstance * h ) const
{
2013-02-02 01:04:25 +03:00
EBonusType type = bonusType ;
2009-04-08 22:55:50 +03:00
int bid = bonusID ;
//check if the bonus if applicable, if not - give primary skill (always possible)
2013-02-12 22:49:40 +03:00
int ssl = h - > getSecSkillLevel ( SecondarySkill ( bid ) ) ; //current sec skill level, used if bonusType == 1
2013-02-02 01:04:25 +03:00
if ( ( type = = SECONDARY_SKILL
2012-12-18 14:24:13 +03:00
& & ( ( ssl = = 3 ) | | ( ! ssl & & ! h - > canLearnSkill ( ) ) ) ) ////hero already has expert level in the skill or (don't know skill and doesn't have free slot)
2013-02-07 02:24:43 +03:00
| | ( type = = SPELL & & ( ! h - > getArt ( ArtifactPosition : : SPELLBOOK ) | | vstd : : contains ( h - > spells , ( ui32 ) bid )
2013-02-13 22:35:43 +03:00
| | ( SpellID ( bid ) . toSpell ( ) - > level > h - > getSecSkillLevel ( SecondarySkill : : WISDOM ) + 2 )
2010-09-26 19:11:50 +03:00
) ) ) //hero doesn't have a spellbook or already knows the spell or doesn't have Wisdom
2009-04-08 22:55:50 +03:00
{
2013-02-02 01:04:25 +03:00
type = PRIM_SKILL ;
2011-12-14 00:23:17 +03:00
bid = ran ( ) % GameConstants : : PRIMARY_SKILLS ;
2009-04-08 22:55:50 +03:00
}
InfoWindow iw ;
2009-04-24 00:09:10 +03:00
iw . soundID = soundBase : : gazebo ;
2009-04-08 22:55:50 +03:00
iw . player = h - > getOwner ( ) ;
iw . text . addTxt ( MetaString : : ADVOB_TXT , 115 ) ;
switch ( type )
{
2013-02-02 01:04:25 +03:00
case PRIM_SKILL :
2013-02-09 00:17:39 +03:00
cb - > changePrimSkill ( h , static_cast < PrimarySkill : : PrimarySkill > ( bid ) , + 1 ) ;
2009-07-16 01:46:00 +03:00
iw . components . push_back ( Component ( Component : : PRIM_SKILL , bid , + 1 , 0 ) ) ;
2009-04-08 22:55:50 +03:00
break ;
2013-02-02 01:04:25 +03:00
case SECONDARY_SKILL :
2013-02-12 22:49:40 +03:00
cb - > changeSecSkill ( h , SecondarySkill ( bid ) , + 1 ) ;
2009-06-10 03:06:35 +03:00
iw . components . push_back ( Component ( Component : : SEC_SKILL , bid , ssl + 1 , 0 ) ) ;
2009-04-08 22:55:50 +03:00
break ;
2013-02-02 01:04:25 +03:00
case SPELL :
2009-04-08 22:55:50 +03:00
{
2013-02-11 02:24:57 +03:00
std : : set < SpellID > hlp ;
hlp . insert ( SpellID ( bid ) ) ;
2013-02-09 00:17:39 +03:00
cb - > changeSpells ( h , true , hlp ) ;
2009-04-08 22:55:50 +03:00
iw . components . push_back ( Component ( Component : : SPELL , bid , 0 , 0 ) ) ;
}
break ;
default :
2013-04-20 14:34:01 +03:00
logGlobal - > errorStream ( ) < < " Error: wrong bonus type ( " < < ( int ) type < < " ) for Scholar! \n " ;
2009-04-08 22:55:50 +03:00
return ;
}
cb - > showInfoDialog ( & iw ) ;
2013-02-09 00:17:39 +03:00
cb - > removeObject ( this ) ;
2009-04-08 22:55:50 +03:00
}
void CGScholar : : initObj ( )
{
blockVisit = true ;
2013-02-02 01:04:25 +03:00
if ( bonusType = = RANDOM )
2009-04-08 22:55:50 +03:00
{
2013-02-02 01:04:25 +03:00
bonusType = static_cast < EBonusType > ( ran ( ) % 3 ) ;
2009-04-08 22:55:50 +03:00
switch ( bonusType )
{
2013-02-02 01:04:25 +03:00
case PRIM_SKILL :
2011-12-14 00:23:17 +03:00
bonusID = ran ( ) % GameConstants : : PRIMARY_SKILLS ;
2009-04-08 22:55:50 +03:00
break ;
2013-02-02 01:04:25 +03:00
case SECONDARY_SKILL :
2011-12-14 00:23:17 +03:00
bonusID = ran ( ) % GameConstants : : SKILL_QUANTITY ;
2009-04-08 22:55:50 +03:00
break ;
2013-02-02 01:04:25 +03:00
case SPELL :
2013-02-11 02:24:57 +03:00
std : : vector < SpellID > possibilities ;
2009-10-23 22:58:21 +03:00
for ( int i = 1 ; i < 6 ; + + i )
cb - > getAllowedSpells ( possibilities , i ) ;
bonusID = possibilities [ ran ( ) % possibilities . size ( ) ] ;
2009-04-08 22:55:50 +03:00
break ;
}
}
}
2009-04-16 03:28:54 +03:00
2009-08-25 18:08:18 +03:00
void CGGarrison : : onHeroVisit ( const CGHeroInstance * h ) const
{
2010-08-13 13:46:08 +03:00
int ally = cb - > gameState ( ) - > getPlayerRelations ( h - > tempOwner , tempOwner ) ;
2010-08-06 16:14:10 +03:00
if ( ! ally & & stacksCount ( ) > 0 ) {
2009-08-25 18:08:18 +03:00
//TODO: Find a way to apply magic garrison effects in battle.
2013-04-20 14:34:01 +03:00
cb - > startBattleI ( h , this ) ;
2009-08-25 18:08:18 +03:00
return ;
}
//New owner.
2010-08-06 16:14:10 +03:00
if ( ! ally )
2013-02-09 00:17:39 +03:00
cb - > setOwner ( this , h - > tempOwner ) ;
2009-08-25 18:08:18 +03:00
2013-05-14 16:42:52 +03:00
cb - > showGarrisonDialog ( id , h - > id , removableUnits ) ;
2009-08-25 18:08:18 +03:00
}
2009-12-20 19:14:14 +02:00
ui8 CGGarrison : : getPassableness ( ) const
{
2010-08-06 16:14:10 +03:00
if ( ! stacksCount ( ) ) //empty - anyone can visit
2011-12-14 00:23:17 +03:00
return GameConstants : : ALL_PLAYERS ;
2013-03-03 20:06:03 +03:00
if ( tempOwner = = PlayerColor : : NEUTRAL ) //neutral guarded - no one can visit
2010-08-06 16:14:10 +03:00
return 0 ;
2012-07-19 21:52:44 +03:00
2010-08-08 17:39:41 +03:00
ui8 mask = 0 ;
2010-08-06 16:14:10 +03:00
TeamState * ts = cb - > gameState ( ) - > getPlayerTeam ( tempOwner ) ;
2013-06-29 16:05:48 +03:00
for ( PlayerColor it : ts - > players )
2013-03-03 20:06:03 +03:00
mask | = 1 < < it . getNum ( ) ; //allies - add to possible visitors
2012-07-19 21:52:44 +03:00
2010-08-06 16:14:10 +03:00
return mask ;
2009-12-20 19:14:14 +02:00
}
2013-04-20 14:34:01 +03:00
void CGGarrison : : battleFinished ( const CGHeroInstance * hero , const BattleResult & result ) const
{
if ( result . winner = = 0 )
onHeroVisit ( hero ) ;
}
2009-04-16 03:28:54 +03:00
void CGOnceVisitable : : onHeroVisit ( const CGHeroInstance * h ) const
{
2013-03-14 23:44:00 +03:00
int sound = soundBase : : sound_todo ;
2012-06-07 06:02:30 +03:00
int txtid ;
2009-04-16 03:28:54 +03:00
switch ( ID )
{
2012-09-23 21:01:04 +03:00
case Obj : : CORPSE :
2012-07-19 21:52:44 +03:00
txtid = 37 ;
2009-04-24 00:09:10 +03:00
sound = soundBase : : MYSTERY ;
2009-04-16 03:28:54 +03:00
break ;
2012-09-23 21:01:04 +03:00
case Obj : : LEAN_TO :
2009-04-24 00:09:10 +03:00
sound = soundBase : : GENIE ;
2009-04-16 03:28:54 +03:00
txtid = 64 ;
break ;
2012-09-23 21:01:04 +03:00
case Obj : : WAGON :
2009-04-24 00:09:10 +03:00
sound = soundBase : : GENIE ;
2009-04-16 03:28:54 +03:00
txtid = 154 ;
break ;
2012-09-23 21:01:04 +03:00
case Obj : : WARRIORS_TOMB :
2012-06-07 06:02:30 +03:00
{
//ask if player wants to search the Tomb
BlockingDialog bd ( true , false ) ;
bd . soundID = soundBase : : GRAVEYARD ;
bd . player = h - > getOwner ( ) ;
bd . text . addTxt ( MetaString : : ADVOB_TXT , 161 ) ;
2013-04-20 14:34:01 +03:00
cb - > showBlockingDialog ( & bd ) ;
2012-06-07 06:02:30 +03:00
return ;
}
2009-04-16 03:28:54 +03:00
break ;
default :
2013-04-09 17:31:36 +03:00
logGlobal - > errorStream ( ) < < " Error: Unknown object ( " < < ID < < " ) treated as CGOnceVisitable! " ;
2009-04-16 03:28:54 +03:00
return ;
}
InfoWindow iw ;
2009-04-24 00:09:10 +03:00
iw . soundID = sound ;
2009-04-16 03:28:54 +03:00
iw . player = h - > getOwner ( ) ;
if ( players . size ( ) ) //we have been already visited...
{
txtid + + ;
2012-09-23 21:01:04 +03:00
if ( ID = = Obj : : WAGON ) //wagon has extra text (for finding art) we need to omit
2009-04-16 03:28:54 +03:00
txtid + + ;
2010-01-01 14:15:20 +02:00
iw . text . addTxt ( MetaString : : ADVOB_TXT , txtid ) ;
2009-04-16 03:28:54 +03:00
}
else //first visit - give bonus!
{
switch ( artOrRes )
{
2009-10-22 08:39:04 +03:00
case 0 : // first visit but empty
2012-09-23 21:01:04 +03:00
if ( ID = = Obj : : CORPSE )
2009-12-01 12:10:42 +02:00
+ + txtid ;
else
txtid + = 2 ;
iw . text . addTxt ( MetaString : : ADVOB_TXT , txtid ) ;
2009-04-16 03:28:54 +03:00
break ;
case 1 : //art
iw . components . push_back ( Component ( Component : : ARTIFACT , bonusType , 0 , 0 ) ) ;
2013-02-07 02:24:43 +03:00
cb - > giveHeroNewArtifact ( h , VLC - > arth - > artifacts [ bonusType ] , ArtifactPosition : : FIRST_AVAILABLE ) ;
2009-12-01 12:10:42 +02:00
iw . text . addTxt ( MetaString : : ADVOB_TXT , txtid ) ;
2012-09-23 21:01:04 +03:00
if ( ID = = Obj : : CORPSE )
2009-12-01 12:10:42 +02:00
{
iw . text < < " %s " ;
2010-11-22 02:34:46 +02:00
iw . text . addReplacement ( MetaString : : ART_NAMES , bonusType ) ;
2009-12-01 12:10:42 +02:00
}
2009-04-16 03:28:54 +03:00
break ;
case 2 : //res
2009-12-01 12:10:42 +02:00
iw . text . addTxt ( MetaString : : ADVOB_TXT , txtid ) ;
2009-12-01 13:47:52 +02:00
iw . components . push_back ( Component ( Component : : RESOURCE , bonusType , bonusVal , 0 ) ) ;
2013-02-04 22:43:16 +03:00
cb - > giveResource ( h - > getOwner ( ) , static_cast < Res : : ERes > ( bonusType ) , bonusVal ) ;
2009-04-16 03:28:54 +03:00
break ;
}
2012-09-23 21:01:04 +03:00
if ( ID = = Obj : : WAGON & & artOrRes = = 1 )
2009-07-12 17:07:36 +03:00
{
iw . text . localStrings . back ( ) . second + + ;
iw . text . addReplacement ( MetaString : : ART_NAMES , bonusType ) ;
}
2009-04-16 03:28:54 +03:00
}
cb - > showInfoDialog ( & iw ) ;
2013-03-03 20:06:03 +03:00
cb - > setObjProperty ( id , 10 , h - > getOwner ( ) . getNum ( ) ) ;
2009-04-16 03:28:54 +03:00
}
const std : : string & CGOnceVisitable : : getHoverText ( ) const
{
2013-01-13 15:40:24 +03:00
const bool visited = wasVisited ( cb - > getCurrentPlayer ( ) ) ;
hoverName = VLC - > generaltexth - > names [ ID ] + " " + visitedTxt ( visited ) ;
2009-04-16 03:28:54 +03:00
return hoverName ;
}
void CGOnceVisitable : : initObj ( )
{
switch ( ID )
{
2012-09-23 21:01:04 +03:00
case Obj : : CORPSE :
2009-04-16 03:28:54 +03:00
{
blockVisit = true ;
int hlp = ran ( ) % 100 ;
if ( hlp < 20 )
{
artOrRes = 1 ;
2009-10-24 22:21:32 +03:00
bonusType = cb - > getRandomArt ( CArtifact : : ART_TREASURE | CArtifact : : ART_MINOR | CArtifact : : ART_MAJOR ) ;
2009-04-16 03:28:54 +03:00
}
else
{
artOrRes = 0 ;
}
}
break ;
2012-09-23 21:01:04 +03:00
case Obj : : LEAN_TO :
2009-04-16 03:28:54 +03:00
{
artOrRes = 2 ;
bonusType = ran ( ) % 6 ; //any basic resource without gold
bonusVal = ran ( ) % 4 + 1 ;
}
2009-11-28 13:26:32 +02:00
break ;
2009-04-16 03:28:54 +03:00
2012-09-23 21:01:04 +03:00
case Obj : : WARRIORS_TOMB :
2009-04-16 03:28:54 +03:00
{
artOrRes = 1 ;
int hlp = ran ( ) % 100 ;
if ( hlp < 30 )
2009-10-24 22:21:32 +03:00
bonusType = cb - > getRandomArt ( CArtifact : : ART_TREASURE ) ;
2009-04-16 03:28:54 +03:00
else if ( hlp < 80 )
2009-10-24 22:21:32 +03:00
bonusType = cb - > getRandomArt ( CArtifact : : ART_MINOR ) ;
2009-04-16 03:28:54 +03:00
else if ( hlp < 95 )
2009-10-24 22:21:32 +03:00
bonusType = cb - > getRandomArt ( CArtifact : : ART_MAJOR ) ;
2009-04-16 03:28:54 +03:00
else
2009-10-24 22:21:32 +03:00
bonusType = cb - > getRandomArt ( CArtifact : : ART_RELIC ) ;
2009-04-16 03:28:54 +03:00
}
break ;
2012-09-23 21:01:04 +03:00
case Obj : : WAGON :
2009-04-16 03:28:54 +03:00
{
int hlp = ran ( ) % 100 ;
if ( hlp < 10 )
{
artOrRes = 0 ; // nothing... :(
}
else if ( hlp < 50 ) //minor or treasure art
{
artOrRes = 1 ;
2009-10-24 22:21:32 +03:00
bonusType = cb - > getRandomArt ( CArtifact : : ART_TREASURE | CArtifact : : ART_MINOR ) ;
2009-04-16 03:28:54 +03:00
}
else //2 - 5 of non-gold resource
{
artOrRes = 2 ;
bonusType = ran ( ) % 6 ;
bonusVal = ran ( ) % 4 + 2 ;
}
}
2009-11-28 13:26:32 +02:00
break ;
2009-04-16 03:28:54 +03:00
}
}
2013-04-20 14:34:01 +03:00
void CGOnceVisitable : : blockingDialogAnswered ( const CGHeroInstance * hero , ui32 answer ) const
2009-04-16 03:28:54 +03:00
{
2013-04-20 14:34:01 +03:00
//must have been Tomb
if ( answer )
2009-04-16 03:28:54 +03:00
{
InfoWindow iw ;
2013-04-20 14:34:01 +03:00
iw . player = hero - > getOwner ( ) ;
2009-04-16 03:28:54 +03:00
iw . components . push_back ( Component ( Component : : MORALE , 0 , - 3 , 0 ) ) ;
if ( players . size ( ) ) //we've been already visited, player found nothing
{
iw . text . addTxt ( MetaString : : ADVOB_TXT , 163 ) ;
}
else //first visit - give artifact
{
iw . text . addTxt ( MetaString : : ADVOB_TXT , 162 ) ;
iw . components . push_back ( Component ( Component : : ARTIFACT , bonusType , 0 , 0 ) ) ;
2009-07-09 22:15:22 +03:00
iw . text . addReplacement ( MetaString : : ART_NAMES , bonusType ) ;
2009-04-16 03:28:54 +03:00
2013-04-20 14:34:01 +03:00
cb - > giveHeroNewArtifact ( hero , VLC - > arth - > artifacts [ bonusType ] , ArtifactPosition : : FIRST_AVAILABLE ) ;
2012-07-19 21:52:44 +03:00
}
2013-04-20 14:34:01 +03:00
if ( ! hero - > hasBonusFrom ( Bonus : : OBJECT , ID ) ) //we don't have modifier from this object yet
2009-08-13 04:03:11 +03:00
{
2012-07-19 21:52:44 +03:00
//ruin morale
2009-08-13 04:03:11 +03:00
GiveBonus gb ;
2013-04-20 14:34:01 +03:00
gb . id = hero - > id . getNum ( ) ;
2013-02-14 02:55:42 +03:00
gb . bonus = Bonus ( Bonus : : ONE_BATTLE , Bonus : : MORALE , Bonus : : OBJECT , - 3 , id . getNum ( ) , " " ) ;
2009-08-13 04:03:11 +03:00
gb . bdescr . addTxt ( MetaString : : ARRAY_TXT , 104 ) ; //Warrior Tomb Visited -3
cb - > giveHeroBonus ( & gb ) ;
2009-04-16 03:28:54 +03:00
}
2009-10-03 14:16:42 +03:00
cb - > showInfoDialog ( & iw ) ;
2013-04-20 14:34:01 +03:00
cb - > setObjProperty ( id , 10 , hero - > getOwner ( ) . getNum ( ) ) ;
2009-08-11 10:50:29 +03:00
}
}
void CBank : : initObj ( )
{
2012-03-03 13:08:01 +03:00
index = VLC - > objh - > bankObjToIndex ( this ) ;
2013-06-26 14:18:27 +03:00
bc = nullptr ;
2009-08-11 10:50:29 +03:00
daycounter = 0 ;
multiplier = 1 ;
}
2009-09-17 17:27:28 +03:00
const std : : string & CBank : : getHoverText ( ) const
{
2013-01-13 15:40:24 +03:00
bool visited = ( bc = = nullptr ) ;
hoverName = VLC - > objh - > creBanksNames [ index ] + " " + visitedTxt ( visited ) ;
2009-09-17 17:27:28 +03:00
return hoverName ;
}
2009-10-24 22:21:32 +03:00
void CBank : : reset ( ui16 var1 ) //prevents desync
2009-08-11 10:50:29 +03:00
{
2009-09-01 17:36:48 +03:00
ui8 chance = 0 ;
2013-06-29 16:05:48 +03:00
for ( auto & elem : VLC - > objh - > banksInfo [ index ] )
2012-07-19 21:52:44 +03:00
{
2013-06-29 16:05:48 +03:00
if ( var1 < ( chance + = elem - > chance ) )
2009-08-26 08:08:59 +03:00
{
2013-06-29 16:05:48 +03:00
bc = elem ;
2009-08-26 08:08:59 +03:00
break ;
}
2009-08-11 10:50:29 +03:00
}
artifacts . clear ( ) ;
2009-10-24 22:21:32 +03:00
}
void CBank : : initialize ( ) const
{
2013-02-19 01:37:22 +03:00
cb - > setObjProperty ( id , ObjProperty : : BANK_RESET , ran ( ) ) ; //synchronous reset
2009-08-26 08:08:59 +03:00
for ( ui8 i = 0 ; i < = 3 ; i + + )
2009-10-24 22:21:32 +03:00
{
2013-02-19 01:37:22 +03:00
for ( ui8 n = 0 ; n < bc - > artifacts [ i ] ; n + + )
2012-07-19 21:52:44 +03:00
{
2013-02-19 01:37:22 +03:00
CArtifact : : EartClass artClass ;
switch ( i )
{
case 0 : artClass = CArtifact : : ART_TREASURE ; break ;
case 1 : artClass = CArtifact : : ART_MINOR ; break ;
case 2 : artClass = CArtifact : : ART_MAJOR ; break ;
case 3 : artClass = CArtifact : : ART_RELIC ; break ;
default : assert ( 0 ) ; continue ;
}
int artID = cb - > getArtSync ( ran ( ) , artClass , true ) ;
cb - > setObjProperty ( id , ObjProperty : : BANK_ADD_ARTIFACT , artID ) ;
2009-08-24 17:59:24 +03:00
}
2009-08-11 10:50:29 +03:00
}
2013-02-19 01:37:22 +03:00
cb - > setObjProperty ( id , ObjProperty : : BANK_INIT_ARMY , ran ( ) ) ; //get army
2009-08-11 10:50:29 +03:00
}
void CBank : : setPropertyDer ( ui8 what , ui32 val )
2009-08-26 08:08:59 +03:00
/// random values are passed as arguments and processed identically on all clients
2009-08-11 10:50:29 +03:00
{
switch ( what )
{
2013-02-19 01:37:22 +03:00
case ObjProperty : : BANK_DAYCOUNTER : //daycounter
2009-08-23 18:02:21 +03:00
if ( val = = 0 )
2010-06-28 08:07:21 +03:00
daycounter = 1 ; //yes, 1
2009-08-23 18:02:21 +03:00
else
daycounter + + ;
2009-08-11 10:50:29 +03:00
break ;
2013-02-19 01:37:22 +03:00
case ObjProperty : : BANK_MULTIPLIER : //multiplier, in percent
2011-12-14 00:23:17 +03:00
multiplier = val / 100.0 ;
2009-08-11 10:50:29 +03:00
break ;
case 13 : //bank preset
2009-12-29 03:07:17 +02:00
bc = VLC - > objh - > banksInfo [ index ] [ val ] ;
2009-08-11 10:50:29 +03:00
break ;
2013-02-19 01:37:22 +03:00
case ObjProperty : : BANK_RESET :
2009-10-24 22:21:32 +03:00
reset ( val % 100 ) ;
2009-08-19 09:56:53 +03:00
break ;
2013-02-19 01:37:22 +03:00
case ObjProperty : : BANK_CLEAR_CONFIG :
2013-06-26 14:18:27 +03:00
bc = nullptr ;
2009-08-19 09:56:53 +03:00
break ;
2013-02-19 01:37:22 +03:00
case ObjProperty : : BANK_CLEAR_ARTIFACTS : //remove rewards from Derelict Ship
2009-08-23 18:02:21 +03:00
artifacts . clear ( ) ;
break ;
2013-02-19 01:37:22 +03:00
case ObjProperty : : BANK_INIT_ARMY : //set ArmedInstance army
2009-08-26 08:08:59 +03:00
{
2009-10-24 22:21:32 +03:00
int upgraded = 0 ;
if ( val % 100 < bc - > upgradeChance ) //once again anti-desync
upgraded = 1 ;
switch ( bc - > guards . size ( ) )
2009-08-26 08:08:59 +03:00
{
2009-10-24 22:21:32 +03:00
case 1 :
2010-03-02 20:13:22 +02:00
for ( int i = 0 ; i < 4 ; + + i )
2013-02-16 17:03:47 +03:00
setCreature ( SlotID ( i ) , bc - > guards [ 0 ] . first , bc - > guards [ 0 ] . second / 5 ) ;
setCreature ( SlotID ( 4 ) , CreatureID ( bc - > guards [ 0 ] . first + upgraded ) , bc - > guards [ 0 ] . second / 5 ) ;
2009-10-24 22:21:32 +03:00
break ;
case 4 :
2009-08-26 08:08:59 +03:00
{
2010-03-24 16:58:17 +02:00
if ( bc - > guards . back ( ) . second ) //all stacks are present
2009-10-24 22:21:32 +03:00
{
2013-06-29 16:05:48 +03:00
for ( auto & elem : bc - > guards )
2010-03-24 16:58:17 +02:00
{
2013-06-29 16:05:48 +03:00
setCreature ( SlotID ( stacksCount ( ) ) , elem . first , elem . second ) ;
2010-03-24 16:58:17 +02:00
}
}
2010-06-26 11:31:31 +03:00
else if ( bc - > guards [ 2 ] . second ) //Wraiths are present, split two stacks in Crypt
2010-03-24 16:58:17 +02:00
{
2013-02-16 17:03:47 +03:00
setCreature ( SlotID ( 0 ) , bc - > guards [ 0 ] . first , bc - > guards [ 0 ] . second / 2 ) ;
setCreature ( SlotID ( 1 ) , bc - > guards [ 1 ] . first , bc - > guards [ 1 ] . second / 2 ) ;
setCreature ( SlotID ( 2 ) , CreatureID ( bc - > guards [ 2 ] . first + upgraded ) , bc - > guards [ 2 ] . second ) ;
setCreature ( SlotID ( 3 ) , bc - > guards [ 1 ] . first , bc - > guards [ 1 ] . second / 2 ) ;
setCreature ( SlotID ( 4 ) , bc - > guards [ 0 ] . first , bc - > guards [ 0 ] . second - ( bc - > guards [ 0 ] . second / 2 ) ) ;
2010-06-26 11:31:31 +03:00
}
else //split both stacks
{
for ( int i = 0 ; i < 3 ; + + i ) //skellies
2013-02-16 17:03:47 +03:00
setCreature ( SlotID ( 2 * i ) , bc - > guards [ 0 ] . first , bc - > guards [ 0 ] . second / 3 ) ;
2010-06-26 11:31:31 +03:00
for ( int i = 0 ; i < 2 ; + + i ) //zombies
2013-02-16 17:03:47 +03:00
setCreature ( SlotID ( 2 * i + 1 ) , bc - > guards [ 1 ] . first , bc - > guards [ 1 ] . second / 2 ) ;
2009-10-24 22:21:32 +03:00
}
2009-08-26 08:08:59 +03:00
}
2009-10-24 22:21:32 +03:00
break ;
default :
2013-04-09 17:31:36 +03:00
logGlobal - > warnStream ( ) < < " Error: Unexpected army data: " < < bc - > guards . size ( ) < < " items found " ;
2009-10-24 22:21:32 +03:00
return ;
2009-08-26 08:08:59 +03:00
}
}
break ;
2013-02-19 01:37:22 +03:00
case ObjProperty : : BANK_ADD_ARTIFACT : //add Artifact
2010-06-28 08:07:21 +03:00
{
2013-02-19 01:37:22 +03:00
artifacts . push_back ( val ) ;
2010-06-28 08:07:21 +03:00
break ;
}
2009-08-11 10:50:29 +03:00
}
}
2012-07-19 21:52:44 +03:00
void CBank : : newTurn ( ) const
2009-08-11 10:50:29 +03:00
{
2013-06-26 14:18:27 +03:00
if ( bc = = nullptr )
2009-08-11 10:50:29 +03:00
{
2013-02-02 11:29:57 +03:00
if ( cb - > getDate ( ) = = 1 )
2009-10-24 22:21:32 +03:00
initialize ( ) ; //initialize on first day
2009-09-25 18:40:28 +03:00
else if ( daycounter > = 28 & & ( subID < 13 | | subID > 16 ) ) //no reset for Emissaries
2009-08-11 10:50:29 +03:00
{
2009-10-24 22:21:32 +03:00
initialize ( ) ;
2013-02-19 01:37:22 +03:00
cb - > setObjProperty ( id , ObjProperty : : BANK_DAYCOUNTER , 0 ) ; //daycounter 0
2013-02-02 11:29:57 +03:00
if ( ID = = Obj : : DERELICT_SHIP & & cb - > getDate ( ) > 1 )
2010-03-24 16:58:17 +02:00
{
2013-02-19 01:37:22 +03:00
cb - > setObjProperty ( id , ObjProperty : : BANK_MULTIPLIER , 0 ) ; //ugly hack to make derelict ships usable only once
cb - > setObjProperty ( id , ObjProperty : : BANK_CLEAR_ARTIFACTS , 0 ) ;
2010-03-24 16:58:17 +02:00
}
2009-08-11 10:50:29 +03:00
}
else
2013-02-19 01:37:22 +03:00
cb - > setObjProperty ( id , ObjProperty : : BANK_DAYCOUNTER , 1 ) ; //daycounter++
2009-08-11 10:50:29 +03:00
}
}
2013-03-03 20:06:03 +03:00
bool CBank : : wasVisited ( PlayerColor player ) const
2012-03-14 16:02:38 +03:00
{
return ! bc ;
}
2009-08-11 10:50:29 +03:00
void CBank : : onHeroVisit ( const CGHeroInstance * h ) const
{
2010-03-24 16:58:17 +02:00
if ( bc )
2009-08-11 10:50:29 +03:00
{
int banktext = 0 ;
switch ( ID )
{
2012-09-23 21:01:04 +03:00
case Obj : : CREATURE_BANK :
banktext = 32 ;
break ;
case Obj : : DERELICT_SHIP :
banktext = 41 ;
break ;
case Obj : : DRAGON_UTOPIA :
banktext = 47 ;
break ;
case Obj : : CRYPT :
banktext = 119 ;
break ;
case Obj : : SHIPWRECK :
banktext = 122 ;
break ;
2009-08-11 10:50:29 +03:00
}
BlockingDialog bd ( true , false ) ;
bd . player = h - > getOwner ( ) ;
2011-06-01 08:10:28 +03:00
bd . soundID = soundBase : : ROGUE ;
2013-01-12 16:53:02 +03:00
bd . text . addTxt ( MetaString : : ADVOB_TXT , banktext ) ;
2012-09-23 21:01:04 +03:00
if ( ID = = Obj : : CREATURE_BANK )
2010-11-22 02:34:46 +02:00
bd . text . addReplacement ( VLC - > objh - > creBanksNames [ index ] ) ;
2013-04-20 14:34:01 +03:00
cb - > showBlockingDialog ( & bd ) ;
2009-08-11 10:50:29 +03:00
}
else
{
InfoWindow iw ;
iw . soundID = soundBase : : GRAVEYARD ;
iw . player = h - > getOwner ( ) ;
2012-09-23 21:01:04 +03:00
if ( ID = = Obj : : CRYPT ) //morale penalty for empty Crypt
2010-03-24 16:58:17 +02:00
{
GiveBonus gbonus ;
2013-02-14 02:55:42 +03:00
gbonus . id = h - > id . getNum ( ) ;
2010-05-02 21:20:26 +03:00
gbonus . bonus . duration = Bonus : : ONE_BATTLE ;
gbonus . bonus . source = Bonus : : OBJECT ;
2011-02-20 20:32:39 +02:00
gbonus . bonus . sid = ID ;
2010-03-24 16:58:17 +02:00
gbonus . bdescr < < " \n " < < VLC - > generaltexth - > arraytxt [ 98 ] ;
2010-05-02 21:20:26 +03:00
gbonus . bonus . type = Bonus : : MORALE ;
2010-03-24 16:58:17 +02:00
gbonus . bonus . val = - 1 ;
cb - > giveHeroBonus ( & gbonus ) ;
iw . text < < VLC - > generaltexth - > advobtxt [ 120 ] ;
iw . components . push_back ( Component ( Component : : MORALE , 0 , - 1 , 0 ) ) ;
}
else
{
iw . text < < VLC - > generaltexth - > advobtxt [ 33 ] ;
2010-11-22 02:34:46 +02:00
iw . text . addReplacement ( VLC - > objh - > creBanksNames [ index ] ) ;
2010-03-24 16:58:17 +02:00
}
2009-04-16 03:28:54 +03:00
cb - > showInfoDialog ( & iw ) ;
2009-08-11 10:50:29 +03:00
}
}
2013-04-20 14:34:01 +03:00
void CBank : : battleFinished ( const CGHeroInstance * hero , const BattleResult & result ) const
2009-08-11 10:50:29 +03:00
{
2013-04-20 14:34:01 +03:00
if ( result . winner = = 0 )
2009-08-11 10:50:29 +03:00
{
int textID = - 1 ;
InfoWindow iw ;
2013-04-20 14:34:01 +03:00
iw . player = hero - > getOwner ( ) ;
2009-09-16 19:16:57 +03:00
MetaString loot ;
2009-08-11 10:50:29 +03:00
switch ( ID )
{
2012-09-23 21:01:04 +03:00
case Obj : : CREATURE_BANK : case Obj : : DRAGON_UTOPIA :
textID = 34 ;
break ;
case Obj : : DERELICT_SHIP :
if ( multiplier )
textID = 43 ;
else
{
GiveBonus gbonus ;
2013-04-20 14:34:01 +03:00
gbonus . id = hero - > id . getNum ( ) ;
2012-09-23 21:01:04 +03:00
gbonus . bonus . duration = Bonus : : ONE_BATTLE ;
gbonus . bonus . source = Bonus : : OBJECT ;
gbonus . bonus . sid = ID ;
gbonus . bdescr < < " \n " < < VLC - > generaltexth - > arraytxt [ 101 ] ;
gbonus . bonus . type = Bonus : : MORALE ;
gbonus . bonus . val = - 1 ;
cb - > giveHeroBonus ( & gbonus ) ;
textID = 42 ;
iw . components . push_back ( Component ( Component : : MORALE , 0 , - 1 , 0 ) ) ;
}
break ;
case Obj : : CRYPT :
if ( bc - > resources . size ( ) ! = 0 )
textID = 121 ;
else
{
iw . components . push_back ( Component ( Component : : MORALE , 0 , - 1 , 0 ) ) ;
GiveBonus gbonus ;
2013-04-20 14:34:01 +03:00
gbonus . id = hero - > id . getNum ( ) ;
2012-09-23 21:01:04 +03:00
gbonus . bonus . duration = Bonus : : ONE_BATTLE ;
gbonus . bonus . source = Bonus : : OBJECT ;
gbonus . bonus . sid = ID ;
gbonus . bdescr < < " \n " < < VLC - > generaltexth - > arraytxt [ ID ] ;
gbonus . bonus . type = Bonus : : MORALE ;
gbonus . bonus . val = - 1 ;
cb - > giveHeroBonus ( & gbonus ) ;
textID = 120 ;
iw . components . push_back ( Component ( Component : : MORALE , 0 , - 1 , 0 ) ) ;
}
break ;
case Obj : : SHIPWRECK :
if ( bc - > resources . size ( ) )
textID = 124 ;
else
textID = 123 ;
break ;
2009-08-11 10:50:29 +03:00
}
2009-09-16 19:16:57 +03:00
2009-08-20 13:07:23 +03:00
//grant resources
2010-03-24 16:58:17 +02:00
if ( textID ! = 42 ) //empty derelict ship gives no cash
{
for ( int it = 0 ; it < bc - > resources . size ( ) ; it + + )
2012-07-19 21:52:44 +03:00
{
2010-03-24 16:58:17 +02:00
if ( bc - > resources [ it ] ! = 0 )
{
iw . components . push_back ( Component ( Component : : RESOURCE , it , bc - > resources [ it ] , 0 ) ) ;
loot < < " %d %s " ;
2010-11-22 02:34:46 +02:00
loot . addReplacement ( iw . components . back ( ) . val ) ;
loot . addReplacement ( MetaString : : RES_NAMES , iw . components . back ( ) . subtype ) ;
2013-04-20 14:34:01 +03:00
cb - > giveResource ( hero - > getOwner ( ) , static_cast < Res : : ERes > ( it ) , bc - > resources [ it ] ) ;
2012-07-19 21:52:44 +03:00
}
2010-03-24 16:58:17 +02:00
}
2009-08-11 10:50:29 +03:00
}
2009-08-20 13:07:23 +03:00
//grant artifacts
2013-06-29 16:05:48 +03:00
for ( auto & elem : artifacts )
2009-08-11 10:50:29 +03:00
{
2013-06-29 16:05:48 +03:00
iw . components . push_back ( Component ( Component : : ARTIFACT , elem , 0 , 0 ) ) ;
2009-09-16 19:16:57 +03:00
loot < < " %s " ;
2013-06-29 16:05:48 +03:00
loot . addReplacement ( MetaString : : ART_NAMES , elem ) ;
cb - > giveHeroNewArtifact ( hero , VLC - > arth - > artifacts [ elem ] , ArtifactPosition : : FIRST_AVAILABLE ) ;
2009-08-11 10:50:29 +03:00
}
2009-09-16 19:16:57 +03:00
//display loot
2010-03-24 16:58:17 +02:00
if ( ! iw . components . empty ( ) )
2009-09-16 19:16:57 +03:00
{
2013-01-15 17:20:48 +03:00
iw . text . addTxt ( MetaString : : ADVOB_TXT , textID ) ;
2009-09-17 09:19:27 +03:00
if ( textID = = 34 )
{
2013-04-20 14:34:01 +03:00
iw . text . addReplacement ( MetaString : : CRE_PL_NAMES , result . casualties [ 1 ] . begin ( ) - > first ) ;
2010-11-22 02:34:46 +02:00
iw . text . addReplacement ( loot . buildList ( ) ) ;
2009-09-17 09:19:27 +03:00
}
cb - > showInfoDialog ( & iw ) ;
2009-09-16 19:16:57 +03:00
}
2009-09-17 09:19:27 +03:00
loot . clear ( ) ;
iw . components . clear ( ) ;
iw . text . clear ( ) ;
2009-09-16 19:16:57 +03:00
2009-08-20 13:07:23 +03:00
//grant creatures
2009-08-11 10:50:29 +03:00
CCreatureSet ourArmy ;
2013-02-07 20:34:50 +03:00
for ( auto it = bc - > creatures . cbegin ( ) ; it ! = bc - > creatures . cend ( ) ; it + + )
2009-08-11 10:50:29 +03:00
{
2013-02-16 17:03:47 +03:00
SlotID slot = ourArmy . getSlotFor ( it - > first ) ;
2010-04-02 05:07:40 +03:00
ourArmy . addToSlot ( slot , it - > first , it - > second ) ;
2009-08-11 10:50:29 +03:00
}
2013-06-29 16:05:48 +03:00
for ( auto & elem : ourArmy . Slots ( ) )
2009-09-17 09:19:27 +03:00
{
2013-06-29 16:05:48 +03:00
iw . components . push_back ( Component ( * elem . second ) ) ;
2009-09-17 09:19:27 +03:00
loot < < " %s " ;
2013-06-29 16:05:48 +03:00
loot . addReplacement ( * elem . second ) ;
2009-09-17 09:19:27 +03:00
}
2010-05-02 21:20:26 +03:00
if ( ourArmy . Slots ( ) . size ( ) )
2009-09-17 09:19:27 +03:00
{
2010-11-22 02:34:46 +02:00
if ( ourArmy . Slots ( ) . size ( ) = = 1 & & ourArmy . Slots ( ) . begin ( ) - > second - > count = = 1 )
2009-09-17 09:19:27 +03:00
iw . text . addTxt ( MetaString : : ADVOB_TXT , 185 ) ;
else
iw . text . addTxt ( MetaString : : ADVOB_TXT , 186 ) ;
2010-11-22 02:34:46 +02:00
iw . text . addReplacement ( loot . buildList ( ) ) ;
2013-04-20 14:34:01 +03:00
iw . text . addReplacement ( hero - > name ) ;
2009-09-17 09:19:27 +03:00
cb - > showInfoDialog ( & iw ) ;
2013-04-20 14:34:01 +03:00
cb - > giveCreatures ( this , hero , ourArmy , false ) ;
2009-09-17 09:19:27 +03:00
}
2013-06-26 14:18:27 +03:00
cb - > setObjProperty ( id , ObjProperty : : BANK_CLEAR_CONFIG , 0 ) ; //bc = nullptr
2009-08-11 10:50:29 +03:00
}
2013-04-20 14:34:01 +03:00
}
2010-11-09 14:33:44 +02:00
2013-04-20 14:34:01 +03:00
void CBank : : blockingDialogAnswered ( const CGHeroInstance * hero , ui32 answer ) const
{
if ( answer )
{
cb - > startBattleI ( hero , this , true ) ;
}
2009-08-11 10:50:29 +03:00
}
2009-09-24 20:54:02 +03:00
void CGPyramid : : initObj ( )
{
2013-02-11 02:24:57 +03:00
std : : vector < SpellID > available ;
2009-09-25 07:05:01 +03:00
cb - > getAllowedSpells ( available , 5 ) ;
2010-08-18 16:42:46 +03:00
if ( available . size ( ) )
{
bc = VLC - > objh - > banksInfo [ 21 ] . front ( ) ; //TODO: remove hardcoded value?
2013-02-19 01:37:22 +03:00
spell = ( available [ ran ( ) % available . size ( ) ] ) ;
2010-08-18 16:42:46 +03:00
}
else
{
2013-04-09 17:31:36 +03:00
logGlobal - > errorStream ( ) < < " No spells available for Pyramid! Object set to empty. " ;
2010-08-18 16:42:46 +03:00
}
2013-02-19 01:37:22 +03:00
setPropertyDer ( ObjProperty : : BANK_INIT_ARMY , ran ( ) ) ; //set guards at game start
2009-09-24 20:54:02 +03:00
}
2009-09-25 18:40:28 +03:00
const std : : string & CGPyramid : : getHoverText ( ) const
{
2013-01-13 15:40:24 +03:00
hoverName = VLC - > objh - > creBanksNames [ 21 ] + " " + visitedTxt ( ( bc = = nullptr ) ) ;
2009-09-25 18:40:28 +03:00
return hoverName ;
}
2009-09-24 20:54:02 +03:00
void CGPyramid : : onHeroVisit ( const CGHeroInstance * h ) const
{
if ( bc )
{
BlockingDialog bd ( true , false ) ;
bd . player = h - > getOwner ( ) ;
2010-08-17 18:16:08 +03:00
bd . soundID = soundBase : : MYSTERY ;
2009-09-24 20:54:02 +03:00
bd . text < < VLC - > generaltexth - > advobtxt [ 105 ] ;
2013-04-20 14:34:01 +03:00
cb - > showBlockingDialog ( & bd ) ;
2009-09-24 20:54:02 +03:00
}
else
{
InfoWindow iw ;
2009-09-25 18:40:28 +03:00
iw . player = h - > getOwner ( ) ;
2009-09-24 20:54:02 +03:00
iw . text < < VLC - > generaltexth - > advobtxt [ 107 ] ;
iw . components . push_back ( Component ( Component : : LUCK , 0 , - 2 , 0 ) ) ;
GiveBonus gb ;
2013-02-14 02:55:42 +03:00
gb . bonus = Bonus ( Bonus : : ONE_BATTLE , Bonus : : LUCK , Bonus : : OBJECT , - 2 , id . getNum ( ) , VLC - > generaltexth - > arraytxt [ 70 ] ) ;
gb . id = h - > id . getNum ( ) ;
2009-09-24 20:54:02 +03:00
cb - > giveHeroBonus ( & gb ) ;
cb - > showInfoDialog ( & iw ) ;
}
}
2013-04-20 14:34:01 +03:00
void CGPyramid : : battleFinished ( const CGHeroInstance * hero , const BattleResult & result ) const
2009-09-24 20:54:02 +03:00
{
2013-04-20 14:34:01 +03:00
if ( result . winner = = 0 )
2009-09-24 20:54:02 +03:00
{
InfoWindow iw ;
2013-04-20 14:34:01 +03:00
iw . player = hero - > getOwner ( ) ;
2009-09-24 20:54:02 +03:00
iw . text . addTxt ( MetaString : : ADVOB_TXT , 106 ) ;
iw . text . addTxt ( MetaString : : SPELL_NAME , spell ) ;
2013-04-20 14:34:01 +03:00
if ( ! hero - > getArt ( ArtifactPosition : : SPELLBOOK ) )
2009-09-25 18:40:28 +03:00
iw . text . addTxt ( MetaString : : ADVOB_TXT , 109 ) ; //no spellbook
2013-04-20 14:34:01 +03:00
else if ( hero - > getSecSkillLevel ( SecondarySkill : : WISDOM ) < 3 )
2009-09-25 18:40:28 +03:00
iw . text . addTxt ( MetaString : : ADVOB_TXT , 108 ) ; //no expert Wisdom
2009-09-24 20:54:02 +03:00
else
{
2013-02-11 02:24:57 +03:00
std : : set < SpellID > spells ;
spells . insert ( SpellID ( spell ) ) ;
2013-04-20 14:34:01 +03:00
cb - > changeSpells ( hero , true , spells ) ;
iw . components . push_back ( Component ( Component : : SPELL , spell , 0 , 0 ) ) ;
2009-09-24 20:54:02 +03:00
}
cb - > showInfoDialog ( & iw ) ;
2013-02-19 01:37:22 +03:00
cb - > setObjProperty ( id , ObjProperty : : BANK_CLEAR_CONFIG , 0 ) ;
2009-09-24 20:54:02 +03:00
}
}
2013-04-20 14:34:01 +03:00
2009-08-11 10:50:29 +03:00
void CGKeys : : setPropertyDer ( ui8 what , ui32 val ) //101-108 - enable key for player 1-8
{
2013-03-03 20:06:03 +03:00
if ( what > = 101 & & what < = ( 100 + PlayerColor : : PLAYER_LIMIT_I ) )
playerKeyMap . find ( PlayerColor ( what - 101 ) ) - > second . insert ( ( ui8 ) val ) ;
2009-08-11 10:50:29 +03:00
}
2009-04-16 03:28:54 +03:00
2013-03-03 20:06:03 +03:00
bool CGKeys : : wasMyColorVisited ( PlayerColor player ) const
2009-08-11 10:50:29 +03:00
{
if ( vstd : : contains ( playerKeyMap [ player ] , subID ) ) //creates set if it's not there
return true ;
else
return false ;
}
2013-01-13 15:40:24 +03:00
const std : : string & CGKeys : : getHoverText ( ) const
{
bool visited = wasMyColorVisited ( cb - > getLocalPlayer ( ) ) ;
hoverName = getName ( ) + " \n " + visitedTxt ( visited ) ;
return hoverName ;
}
2012-07-08 19:36:20 +03:00
const std : : string CGKeys : : getName ( ) const
{
std : : string name ;
name = VLC - > generaltexth - > tentColors [ subID ] + " " + VLC - > generaltexth - > names [ ID ] ;
return name ;
}
2013-03-03 20:06:03 +03:00
bool CGKeymasterTent : : wasVisited ( PlayerColor player ) const
2012-03-14 16:02:38 +03:00
{
return wasMyColorVisited ( player ) ;
}
2009-08-11 10:50:29 +03:00
void CGKeymasterTent : : onHeroVisit ( const CGHeroInstance * h ) const
{
2013-01-12 13:32:03 +03:00
int txt_id ;
2009-08-11 10:50:29 +03:00
if ( ! wasMyColorVisited ( h - > getOwner ( ) ) )
{
2013-03-03 20:06:03 +03:00
cb - > setObjProperty ( id , h - > tempOwner . getNum ( ) + 101 , subID ) ;
2013-01-12 13:32:03 +03:00
txt_id = 19 ;
2009-04-16 03:28:54 +03:00
}
2009-08-11 10:50:29 +03:00
else
2013-01-12 13:32:03 +03:00
txt_id = 20 ;
showInfoDialog ( h , txt_id , soundBase : : CAVEHEAD ) ;
2009-08-11 10:50:29 +03:00
}
void CGBorderGuard : : initObj ( )
{
2012-07-19 21:52:44 +03:00
//ui32 m13489val = subID; //store color as quest info
2009-08-11 10:50:29 +03:00
blockVisit = true ;
2009-05-24 01:57:39 +03:00
}
2009-07-19 04:00:19 +03:00
2012-07-08 19:36:20 +03:00
void CGBorderGuard : : getVisitText ( MetaString & text , std : : vector < Component > & components , bool isCustom , bool FirstVisit , const CGHeroInstance * h ) const
{
text < < std : : pair < ui8 , ui32 > ( 11 , 18 ) ;
}
void CGBorderGuard : : getRolloverText ( MetaString & text , bool onHover ) const
{
if ( ! onHover )
text < < VLC - > generaltexth - > tentColors [ subID ] < < " " < < VLC - > generaltexth - > names [ Obj : : KEYMASTER ] ;
}
2012-07-19 12:10:55 +03:00
bool CGBorderGuard : : checkQuest ( const CGHeroInstance * h ) const
{
return wasMyColorVisited ( h - > tempOwner ) ;
}
2012-07-19 21:52:44 +03:00
void CGBorderGuard : : onHeroVisit ( const CGHeroInstance * h ) const
2009-08-11 10:50:29 +03:00
{
if ( wasMyColorVisited ( h - > getOwner ( ) ) )
{
BlockingDialog bd ( true , false ) ;
bd . player = h - > getOwner ( ) ;
bd . soundID = soundBase : : QUEST ;
bd . text . addTxt ( MetaString : : ADVOB_TXT , 17 ) ;
2013-04-20 14:34:01 +03:00
cb - > showBlockingDialog ( & bd ) ;
2012-07-19 21:52:44 +03:00
}
2009-08-11 10:50:29 +03:00
else
{
2013-01-12 13:32:03 +03:00
showInfoDialog ( h , 18 , soundBase : : CAVEHEAD ) ;
2012-07-06 22:12:04 +03:00
2012-07-08 19:36:20 +03:00
AddQuest aq ;
2012-10-03 17:49:29 +03:00
aq . quest = QuestInfo ( quest , this , visitablePos ( ) ) ;
2012-07-08 19:36:20 +03:00
aq . player = h - > tempOwner ;
cb - > sendAndApply ( & aq ) ;
//TODO: add this quest only once OR check for multiple instances later
2009-08-11 10:50:29 +03:00
}
}
2013-04-20 14:34:01 +03:00
void CGBorderGuard : : blockingDialogAnswered ( const CGHeroInstance * hero , ui32 answer ) const
2009-08-11 10:50:29 +03:00
{
2013-04-20 14:34:01 +03:00
if ( answer )
2013-02-09 00:17:39 +03:00
cb - > removeObject ( this ) ;
2009-08-11 10:50:29 +03:00
}
2012-07-19 21:52:44 +03:00
void CGBorderGate : : onHeroVisit ( const CGHeroInstance * h ) const //TODO: passability
2009-08-11 10:50:29 +03:00
{
if ( ! wasMyColorVisited ( h - > getOwner ( ) ) )
{
2013-01-12 13:32:03 +03:00
showInfoDialog ( h , 18 , 0 ) ;
2012-07-08 19:36:20 +03:00
AddQuest aq ;
2012-10-03 17:49:29 +03:00
aq . quest = QuestInfo ( quest , this , visitablePos ( ) ) ;
2012-07-08 19:36:20 +03:00
aq . player = h - > tempOwner ;
cb - > sendAndApply ( & aq ) ;
2009-08-11 10:50:29 +03:00
}
}
2009-12-20 19:14:14 +02:00
ui8 CGBorderGate : : getPassableness ( ) const
{
ui8 ret = 0 ;
2013-03-03 20:06:03 +03:00
for ( int i = 0 ; i < PlayerColor : : PLAYER_LIMIT_I ; i + + )
ret | = wasMyColorVisited ( PlayerColor ( i ) ) < < i ;
2009-12-20 19:14:14 +02:00
return ret ;
}
2009-08-11 10:50:29 +03:00
void CGMagi : : initObj ( )
{
2012-09-23 21:01:04 +03:00
if ( ID = = Obj : : EYE_OF_MAGI )
2009-08-11 10:50:29 +03:00
{
blockVisit = true ;
2009-08-13 04:03:11 +03:00
eyelist [ subID ] . push_back ( id ) ;
2009-08-11 10:50:29 +03:00
}
}
void CGMagi : : onHeroVisit ( const CGHeroInstance * h ) const
{
2012-09-23 21:01:04 +03:00
if ( ID = = Obj : : HUT_OF_MAGI )
2009-08-11 10:50:29 +03:00
{
2013-03-29 22:15:52 +03:00
showInfoDialog ( h , 61 , soundBase : : LIGHTHOUSE ) ;
2010-08-18 13:52:30 +03:00
2013-03-29 22:15:52 +03:00
if ( ! eyelist [ subID ] . empty ( ) )
2009-08-13 04:03:11 +03:00
{
2013-03-29 22:15:52 +03:00
CenterView cv ;
cv . player = h - > tempOwner ;
2009-08-13 04:03:11 +03:00
cv . focusTime = 2000 ;
2013-03-29 22:15:52 +03:00
FoWChange fw ;
fw . player = h - > tempOwner ;
fw . mode = 1 ;
2013-06-29 16:05:48 +03:00
for ( auto it : eyelist [ subID ] )
2013-03-29 22:15:52 +03:00
{
const CGObjectInstance * eye = cb - > getObj ( it ) ;
cb - > getTilesInRange ( fw . tiles , eye - > pos , 10 , h - > tempOwner , 1 ) ;
cb - > sendAndApply ( & fw ) ;
cv . pos = eye - > pos ;
cb - > sendAndApply ( & cv ) ;
}
cv . pos = h - > getPosition ( false ) ;
2009-08-11 10:50:29 +03:00
cb - > sendAndApply ( & cv ) ;
2012-07-19 21:52:44 +03:00
}
2010-08-18 13:52:30 +03:00
}
2012-09-23 21:01:04 +03:00
else if ( ID = = Obj : : EYE_OF_MAGI )
2010-08-18 13:52:30 +03:00
{
2013-01-12 13:32:03 +03:00
showInfoDialog ( h , 48 , soundBase : : invalid ) ;
2010-08-18 13:52:30 +03:00
}
2010-08-17 19:26:48 +03:00
2010-08-18 13:52:30 +03:00
}
2009-07-19 04:00:19 +03:00
void CGBoat : : initObj ( )
{
2013-06-26 14:18:27 +03:00
hero = nullptr ;
2009-07-19 10:16:33 +03:00
}
void CGSirens : : initObj ( )
{
blockVisit = true ;
}
const std : : string & CGSirens : : getHoverText ( ) const
{
getNameVis ( hoverName ) ;
return hoverName ;
}
void CGSirens : : onHeroVisit ( const CGHeroInstance * h ) const
{
InfoWindow iw ;
iw . soundID = soundBase : : DANGER ;
iw . player = h - > tempOwner ;
2010-05-02 21:20:26 +03:00
if ( h - > hasBonusFrom ( Bonus : : OBJECT , ID ) ) //has already visited Sirens
2009-07-19 10:16:33 +03:00
{
2013-01-12 13:32:03 +03:00
iw . text . addTxt ( MetaString : : ADVOB_TXT , 133 ) ;
2009-07-19 10:16:33 +03:00
}
else
{
2010-05-02 21:20:26 +03:00
giveDummyBonus ( h - > id , Bonus : : ONE_BATTLE ) ;
2013-02-04 22:43:16 +03:00
TExpType xp = 0 ;
2010-11-27 22:17:28 +02:00
2013-06-29 16:05:48 +03:00
for ( auto i = h - > Slots ( ) . begin ( ) ; i ! = h - > Slots ( ) . end ( ) ; i + + )
2009-07-19 10:16:33 +03:00
{
2010-11-27 22:17:28 +02:00
TQuantity drown = i - > second - > count * 0.3 ;
2009-07-19 10:16:33 +03:00
if ( drown )
{
2010-11-27 22:17:28 +02:00
cb - > changeStackCount ( StackLocation ( h , i - > first ) , - drown ) ;
2010-11-22 02:34:46 +02:00
xp + = drown * i - > second - > type - > valOfBonuses ( Bonus : : STACK_HEALTH ) ;
2009-07-19 10:16:33 +03:00
}
}
if ( xp )
{
2011-02-12 20:48:11 +02:00
xp = h - > calculateXp ( xp ) ;
2013-01-12 13:32:03 +03:00
iw . text . addTxt ( MetaString : : ADVOB_TXT , 132 ) ;
2009-07-19 10:16:33 +03:00
iw . text . addReplacement ( xp ) ;
2013-02-09 00:17:39 +03:00
cb - > changePrimSkill ( h , PrimarySkill : : EXPERIENCE , xp , false ) ;
2009-07-19 10:16:33 +03:00
}
else
{
2013-01-12 13:32:03 +03:00
iw . text . addTxt ( MetaString : : ADVOB_TXT , 134 ) ;
2009-07-19 10:16:33 +03:00
}
}
cb - > showInfoDialog ( & iw ) ;
2011-02-12 20:48:11 +02:00
2009-07-26 06:33:13 +03:00
}
//bool IShipyard::validLocation() const
//{
// std::vector<int3> offsets;
// getOutOffsets(offsets);
//
// TerrainTile *tile;
// for(int i = 0; i < offsets.size(); i++)
2012-11-06 19:39:29 +03:00
// if((tile = IObjectInterface::cb->getTile(o->pos + offsets[i])) && tile->terType == TerrainTile::water) //tile is in the map and is water
2009-07-26 06:33:13 +03:00
// return true;
// return false;
//}
2010-03-11 01:16:30 +02:00
int3 IBoatGenerator : : bestLocation ( ) const
2009-07-26 06:33:13 +03:00
{
std : : vector < int3 > offsets ;
getOutOffsets ( offsets ) ;
2013-06-29 16:05:48 +03:00
for ( auto & offset : offsets )
2010-06-26 15:57:16 +03:00
{
2013-06-29 16:05:48 +03:00
if ( const TerrainTile * tile = IObjectInterface : : cb - > getTile ( o - > pos + offset , false ) ) //tile is in the map
2010-06-26 15:57:16 +03:00
{
2012-11-06 19:39:29 +03:00
if ( tile - > terType = = ETerrainType : : WATER & & ( ! tile - > blocked | | tile - > blockingObjects . front ( ) - > ID = = 8 ) ) //and is water and is not blocked or is blocked by boat
2013-06-29 16:05:48 +03:00
return o - > pos + offset ;
2010-06-26 15:57:16 +03:00
}
}
return int3 ( - 1 , - 1 , - 1 ) ;
2009-07-26 06:33:13 +03:00
}
2013-07-21 13:08:32 +03:00
IBoatGenerator : : EGeneratorState IBoatGenerator : : shipyardStatus ( ) const
2009-07-26 06:33:13 +03:00
{
int3 tile = bestLocation ( ) ;
2011-05-10 01:20:47 +03:00
const TerrainTile * t = IObjectInterface : : cb - > getTile ( tile ) ;
2009-07-26 06:33:13 +03:00
if ( ! t )
2012-09-23 21:01:04 +03:00
return TILE_BLOCKED ; //no available water
2009-07-26 06:33:13 +03:00
else if ( ! t - > blockingObjects . size ( ) )
2012-09-23 21:01:04 +03:00
return GOOD ; //OK
else if ( t - > blockingObjects . front ( ) - > ID = = Obj : : BOAT )
return BOAT_ALREADY_BUILT ; //blocked with boat
2009-07-26 06:33:13 +03:00
else
2012-09-23 21:01:04 +03:00
return TILE_BLOCKED ; //blocked
2009-07-26 06:33:13 +03:00
}
2010-03-11 01:16:30 +02:00
int IBoatGenerator : : getBoatType ( ) const
{
//We make good ships by default
return 1 ;
}
2012-07-19 21:52:44 +03:00
IBoatGenerator : : IBoatGenerator ( const CGObjectInstance * O )
2010-03-11 01:16:30 +02:00
: o ( O )
{
}
2010-07-13 08:25:40 +03:00
void IBoatGenerator : : getProblemText ( MetaString & out , const CGHeroInstance * visitor ) const
{
2013-07-21 13:08:32 +03:00
switch ( shipyardStatus ( ) )
2010-07-13 08:25:40 +03:00
{
2012-09-23 21:01:04 +03:00
case BOAT_ALREADY_BUILT :
2010-07-13 08:25:40 +03:00
out . addTxt ( MetaString : : GENERAL_TXT , 51 ) ;
break ;
2012-09-23 21:01:04 +03:00
case TILE_BLOCKED :
2010-07-13 08:25:40 +03:00
if ( visitor )
{
out . addTxt ( MetaString : : GENERAL_TXT , 134 ) ;
out . addReplacement ( visitor - > name ) ;
}
else
out . addTxt ( MetaString : : ADVOB_TXT , 189 ) ;
break ;
2012-09-23 21:01:04 +03:00
case NO_WATER :
2013-04-09 17:31:36 +03:00
logGlobal - > errorStream ( ) < < " Shipyard without water!!! " < < o - > pos < < " \t " < < o - > id ;
2010-07-13 08:25:40 +03:00
return ;
}
}
2010-03-11 01:16:30 +02:00
void IShipyard : : getBoatCost ( std : : vector < si32 > & cost ) const
{
2011-12-14 00:23:17 +03:00
cost . resize ( GameConstants : : RESOURCE_QUANTITY ) ;
2013-01-13 15:40:24 +03:00
cost [ Res : : WOOD ] = 10 ;
cost [ Res : : GOLD ] = 1000 ;
2010-03-11 01:16:30 +02:00
}
2012-07-19 21:52:44 +03:00
IShipyard : : IShipyard ( const CGObjectInstance * O )
2010-03-11 01:16:30 +02:00
: IBoatGenerator ( O )
{
}
2009-07-26 06:33:13 +03:00
IShipyard * IShipyard : : castFrom ( CGObjectInstance * obj )
{
2010-07-13 08:25:40 +03:00
if ( ! obj )
2013-06-26 14:18:27 +03:00
return nullptr ;
2010-07-13 08:25:40 +03:00
2012-09-23 21:01:04 +03:00
if ( obj - > ID = = Obj : : TOWN )
2009-07-26 06:33:13 +03:00
{
return static_cast < CGTownInstance * > ( obj ) ;
}
2012-09-23 21:01:04 +03:00
else if ( obj - > ID = = Obj : : SHIPYARD )
2009-07-26 06:33:13 +03:00
{
return static_cast < CGShipyard * > ( obj ) ;
}
else
{
2013-06-26 14:18:27 +03:00
return nullptr ;
2009-07-26 06:33:13 +03:00
}
}
const IShipyard * IShipyard : : castFrom ( const CGObjectInstance * obj )
{
return castFrom ( const_cast < CGObjectInstance * > ( obj ) ) ;
}
CGShipyard : : CGShipyard ( )
: IShipyard ( this )
{
}
void CGShipyard : : getOutOffsets ( std : : vector < int3 > & offsets ) const
{
2010-07-13 08:25:40 +03:00
// H J L K I
// A x S x B
// C E G F D
offsets + = int3 ( - 3 , 0 , 0 ) , int3 ( 1 , 0 , 0 ) , //AB
int3 ( - 3 , 1 , 0 ) , int3 ( 1 , 1 , 0 ) , int3 ( - 2 , 1 , 0 ) , int3 ( 0 , 1 , 0 ) , int3 ( - 1 , 1 , 0 ) , //CDEFG
int3 ( - 3 , - 1 , 0 ) , int3 ( 1 , - 1 , 0 ) , int3 ( - 2 , - 1 , 0 ) , int3 ( 0 , - 1 , 0 ) , int3 ( - 1 , - 1 , 0 ) ; //HIJKL
2009-07-26 06:33:13 +03:00
}
void CGShipyard : : onHeroVisit ( const CGHeroInstance * h ) const
{
2010-08-13 13:46:08 +03:00
if ( ! cb - > gameState ( ) - > getPlayerRelations ( tempOwner , h - > tempOwner ) )
2013-02-09 00:17:39 +03:00
cb - > setOwner ( this , h - > tempOwner ) ;
2009-07-26 06:33:13 +03:00
2013-07-21 13:08:32 +03:00
auto s = shipyardStatus ( ) ;
2012-09-30 13:35:17 +03:00
if ( s ! = IBoatGenerator : : GOOD )
2009-07-26 06:33:13 +03:00
{
InfoWindow iw ;
iw . player = tempOwner ;
2010-07-13 08:25:40 +03:00
getProblemText ( iw . text , h ) ;
2009-07-26 06:33:13 +03:00
cb - > showInfoDialog ( & iw ) ;
}
else
{
2013-02-14 02:55:42 +03:00
openWindow ( OpenWindow : : SHIPYARD_WINDOW , id . getNum ( ) , h - > id . getNum ( ) ) ;
2009-07-26 06:33:13 +03:00
}
2009-08-12 05:02:58 +03:00
}
2009-08-19 09:56:53 +03:00
2012-07-19 21:52:44 +03:00
void CCartographer : : onHeroVisit ( const CGHeroInstance * h ) const
2009-08-19 09:56:53 +03:00
{
2012-03-14 16:02:38 +03:00
if ( ! wasVisited ( h - > getOwner ( ) ) ) //if hero has not visited yet this cartographer
2009-08-19 09:56:53 +03:00
{
2013-02-09 15:56:35 +03:00
if ( cb - > getResource ( h - > tempOwner , Res : : GOLD ) > = 1000 ) //if he can afford a map
2009-08-19 09:56:53 +03:00
{
2009-08-19 13:59:42 +03:00
//ask if he wants to buy one
2012-07-06 23:19:54 +03:00
int text = 0 ;
2009-12-30 12:02:31 +02:00
switch ( subID )
2009-08-19 09:56:53 +03:00
{
2009-12-30 12:02:31 +02:00
case 0 :
text = 25 ;
break ;
case 1 :
2009-08-19 09:56:53 +03:00
text = 26 ;
2009-12-30 12:02:31 +02:00
break ;
case 2 :
2009-08-19 09:56:53 +03:00
text = 27 ;
2009-12-30 12:02:31 +02:00
break ;
2012-07-19 21:52:44 +03:00
default :
2013-04-09 17:31:36 +03:00
logGlobal - > warnStream ( ) < < " Unrecognized subtype of cartographer " ;
2009-08-19 09:56:53 +03:00
}
2012-07-06 23:19:54 +03:00
assert ( text ) ;
2009-08-19 09:56:53 +03:00
BlockingDialog bd ( true , false ) ;
bd . player = h - > getOwner ( ) ;
bd . soundID = soundBase : : LIGHTHOUSE ;
bd . text . addTxt ( MetaString : : ADVOB_TXT , text ) ;
2013-04-20 14:34:01 +03:00
cb - > showBlockingDialog ( & bd ) ;
2009-08-19 09:56:53 +03:00
}
2009-08-19 13:59:42 +03:00
else //if he cannot afford
2009-08-19 09:56:53 +03:00
{
2013-01-12 13:32:03 +03:00
showInfoDialog ( h , 28 , soundBase : : CAVEHEAD ) ;
2009-08-19 09:56:53 +03:00
}
2012-07-19 21:52:44 +03:00
}
2009-08-19 13:59:42 +03:00
else //if he already visited carographer
2009-08-19 09:56:53 +03:00
{
2013-01-12 13:32:03 +03:00
showInfoDialog ( h , 24 , soundBase : : CAVEHEAD ) ;
2009-08-19 09:56:53 +03:00
}
}
2009-08-19 13:59:42 +03:00
2013-04-20 14:34:01 +03:00
void CCartographer : : blockingDialogAnswered ( const CGHeroInstance * hero , ui32 answer ) const
2009-08-19 09:56:53 +03:00
{
2013-04-20 14:34:01 +03:00
if ( answer ) //if hero wants to buy map
2009-08-19 09:56:53 +03:00
{
2013-04-20 14:34:01 +03:00
cb - > giveResource ( hero - > tempOwner , Res : : GOLD , - 1000 ) ;
2009-08-19 09:56:53 +03:00
FoWChange fw ;
2010-07-20 12:16:48 +03:00
fw . mode = 1 ;
2013-04-20 14:34:01 +03:00
fw . player = hero - > tempOwner ;
2009-08-19 09:56:53 +03:00
2009-11-14 22:14:15 +02:00
//subIDs of different types of cartographers:
//water = 0; land = 1; underground = 2;
2013-04-20 14:34:01 +03:00
cb - > getAllTiles ( fw . tiles , hero - > tempOwner , subID - 1 , ! subID + 1 ) ; //reveal appropriate tiles
2009-08-19 09:56:53 +03:00
cb - > sendAndApply ( & fw ) ;
2013-04-20 14:34:01 +03:00
cb - > setObjProperty ( id , 10 , hero - > tempOwner . getNum ( ) ) ;
2009-08-19 09:56:53 +03:00
}
2009-08-19 13:59:42 +03:00
}
2009-09-21 12:00:33 +03:00
2010-02-06 15:49:14 +02:00
void CGDenOfthieves : : onHeroVisit ( const CGHeroInstance * h ) const
{
2012-03-07 17:05:54 +03:00
cb - > showThievesGuildWindow ( h - > tempOwner , id ) ;
2010-02-10 04:56:00 +02:00
}
void CGObelisk : : onHeroVisit ( const CGHeroInstance * h ) const
{
InfoWindow iw ;
iw . player = h - > tempOwner ;
2010-08-06 16:14:10 +03:00
TeamState * ts = cb - > gameState ( ) - > getPlayerTeam ( h - > tempOwner ) ;
assert ( ts ) ;
2013-03-03 20:06:03 +03:00
TeamID team = ts - > id ;
2012-07-19 21:52:44 +03:00
2012-03-14 16:02:38 +03:00
if ( ! wasVisited ( team ) )
2010-02-10 04:56:00 +02:00
{
iw . text . addTxt ( MetaString : : ADVOB_TXT , 96 ) ;
cb - > sendAndApply ( & iw ) ;
2013-03-03 20:06:03 +03:00
cb - > setObjProperty ( id , 20 , h - > tempOwner . getNum ( ) ) ; //increment general visited obelisks counter
2010-02-10 04:56:00 +02:00
2013-03-03 20:06:03 +03:00
openWindow ( OpenWindow : : PUZZLE_MAP , h - > tempOwner . getNum ( ) ) ;
2010-02-10 04:56:00 +02:00
2013-03-03 20:06:03 +03:00
cb - > setObjProperty ( id , 10 , h - > tempOwner . getNum ( ) ) ; //mark that particular obelisk as visited
2010-02-10 04:56:00 +02:00
}
else
{
iw . text . addTxt ( MetaString : : ADVOB_TXT , 97 ) ;
cb - > sendAndApply ( & iw ) ;
}
}
void CGObelisk : : initObj ( )
{
obeliskCount + + ;
}
const std : : string & CGObelisk : : getHoverText ( ) const
{
2013-01-13 15:40:24 +03:00
bool visited = wasVisited ( cb - > getLocalPlayer ( ) ) ;
hoverName = VLC - > generaltexth - > names [ ID ] + " " + visitedTxt ( visited ) ;
2010-02-10 04:56:00 +02:00
return hoverName ;
}
void CGObelisk : : setPropertyDer ( ui8 what , ui32 val )
{
CPlayersVisited : : setPropertyDer ( what , val ) ;
switch ( what )
{
case 20 :
2013-03-03 20:06:03 +03:00
assert ( val < PlayerColor : : PLAYER_LIMIT_I ) ;
visited [ TeamID ( val ) ] + + ;
2010-07-14 04:08:27 +03:00
2013-03-03 20:06:03 +03:00
if ( visited [ TeamID ( val ) ] > obeliskCount )
2010-07-14 04:08:27 +03:00
{
2013-04-09 17:31:36 +03:00
logGlobal - > errorStream ( ) < < " Error: Visited " < < visited [ TeamID ( val ) ] < < " \t \t " < < obeliskCount ;
2010-07-14 04:08:27 +03:00
assert ( 0 ) ;
}
2010-02-10 04:56:00 +02:00
break ;
}
}
void CGLighthouse : : onHeroVisit ( const CGHeroInstance * h ) const
{
if ( h - > tempOwner ! = tempOwner )
{
2013-03-03 20:06:03 +03:00
PlayerColor oldOwner = tempOwner ;
2013-02-09 00:17:39 +03:00
cb - > setOwner ( this , h - > tempOwner ) ; //not ours? flag it!
2013-01-12 13:32:03 +03:00
showInfoDialog ( h , 69 , soundBase : : LIGHTHOUSE ) ;
2010-02-10 04:56:00 +02:00
giveBonusTo ( h - > tempOwner ) ;
2013-03-03 20:06:03 +03:00
if ( oldOwner < PlayerColor : : PLAYER_LIMIT ) //remove bonus from old owner
2010-02-10 04:56:00 +02:00
{
RemoveBonus rb ( RemoveBonus : : PLAYER ) ;
2013-03-03 20:06:03 +03:00
rb . whoID = oldOwner . getNum ( ) ;
2010-05-02 21:20:26 +03:00
rb . source = Bonus : : OBJECT ;
2013-02-14 02:55:42 +03:00
rb . id = id . getNum ( ) ;
2010-02-10 04:56:00 +02:00
cb - > sendAndApply ( & rb ) ;
}
}
}
void CGLighthouse : : initObj ( )
{
2013-03-03 20:06:03 +03:00
if ( tempOwner < PlayerColor : : PLAYER_LIMIT )
2010-02-10 04:56:00 +02:00
{
giveBonusTo ( tempOwner ) ;
}
}
const std : : string & CGLighthouse : : getHoverText ( ) const
{
hoverName = VLC - > generaltexth - > names [ ID ] ;
//TODO: owned by %s player
return hoverName ;
}
2013-03-03 20:06:03 +03:00
void CGLighthouse : : giveBonusTo ( PlayerColor player ) const
2010-02-10 04:56:00 +02:00
{
GiveBonus gb ( GiveBonus : : PLAYER ) ;
2010-05-02 21:20:26 +03:00
gb . bonus . type = Bonus : : SEA_MOVEMENT ;
2010-02-10 04:56:00 +02:00
gb . bonus . val = 500 ;
2013-03-03 20:06:03 +03:00
gb . id = player . getNum ( ) ;
2010-05-02 21:20:26 +03:00
gb . bonus . duration = Bonus : : PERMANENT ;
gb . bonus . source = Bonus : : OBJECT ;
2013-02-14 02:55:42 +03:00
gb . bonus . sid = id . getNum ( ) ;
2010-02-10 04:56:00 +02:00
cb - > sendAndApply ( & gb ) ;
2010-05-02 21:20:26 +03:00
}
void CArmedInstance : : randomizeArmy ( int type )
{
int max = VLC - > creh - > creatures . size ( ) ;
2013-06-29 16:05:48 +03:00
for ( auto & elem : stacks )
2010-05-02 21:20:26 +03:00
{
2013-06-29 16:05:48 +03:00
int randID = elem . second - > idRand ;
2010-11-22 02:34:46 +02:00
if ( randID > max )
2010-05-02 21:20:26 +03:00
{
2012-09-28 13:17:07 +03:00
int level = ( randID - VLC - > creh - > creatures . size ( ) ) / 2 - 1 ;
bool upgrade = ! ( randID % 2 ) ;
2013-06-29 16:05:48 +03:00
elem . second - > setType ( VLC - > townh - > factions [ type ] - > town - > creatures [ level ] [ upgrade ] ) ;
2010-11-22 02:34:46 +02:00
randID = - 1 ;
2010-05-02 21:20:26 +03:00
}
2013-06-29 16:05:48 +03:00
assert ( elem . second - > armyObj = = this ) ;
2010-05-02 21:20:26 +03:00
}
return ;
}
CArmedInstance : : CArmedInstance ( )
{
2013-06-26 14:18:27 +03:00
battle = nullptr ;
2010-05-02 21:20:26 +03:00
}
2013-01-13 15:40:24 +03:00
//int CArmedInstance::valOfGlobalBonuses(CSelector selector) const
//{
//// if (tempOwner != NEUTRAL_PLAYER)
// return cb->gameState()->players[tempOwner].valOfBonuses(selector);
//}
2010-09-25 23:23:55 +03:00
2011-02-04 16:58:14 +02:00
void CArmedInstance : : updateMoraleBonusFromArmy ( )
{
if ( ! validTypes ( false ) ) //object not randomized, don't bother
return ;
2013-07-02 15:08:30 +03:00
Bonus * b = getBonusList ( ) . getFirst ( Selector : : sourceType ( Bonus : : ARMY ) . And ( Selector : : type ( Bonus : : MORALE ) ) ) ;
2011-02-04 16:58:14 +02:00
if ( ! b )
{
b = new Bonus ( Bonus : : PERMANENT , Bonus : : MORALE , Bonus : : ARMY , 0 , - 1 ) ;
addNewBonus ( b ) ;
}
//number of alignments and presence of undead
2013-01-10 21:53:49 +03:00
std : : set < TFaction > factions ;
bool hasUndead = false ;
2013-06-29 16:05:48 +03:00
for ( auto slot : Slots ( ) )
2011-02-04 16:58:14 +02:00
{
2013-01-10 21:53:49 +03:00
const CStackInstance * inst = slot . second ;
const CCreature * creature = VLC - > creh - > creatures [ inst - > getCreatureID ( ) ] ;
factions . insert ( creature - > faction ) ;
// Check for undead flag instead of faction (undead mummies are neutral)
hasUndead | = inst - > hasBonusOfType ( Bonus : : UNDEAD ) ;
}
2013-04-27 11:11:20 +03:00
size_t factionsInArmy = factions . size ( ) ; //town garrison seems to take both sets into account
2013-01-10 21:53:49 +03:00
// Take Angelic Alliance troop-mixing freedom of non-evil units into account.
if ( hasBonusOfType ( Bonus : : NONEVIL_ALIGNMENT_MIX ) )
{
size_t mixableFactions = 0 ;
2013-06-29 16:05:48 +03:00
for ( TFaction f : factions )
2013-01-10 21:53:49 +03:00
{
2013-04-21 15:49:26 +03:00
if ( VLC - > townh - > factions [ f ] - > alignment ! = EAlignment : : EVIL )
2013-01-10 21:53:49 +03:00
mixableFactions + + ;
}
if ( mixableFactions > 0 )
factionsInArmy - = mixableFactions - 1 ;
2011-02-04 16:58:14 +02:00
}
2012-07-19 21:52:44 +03:00
2013-01-10 21:53:49 +03:00
if ( factionsInArmy = = 1 )
2011-02-04 16:58:14 +02:00
{
b - > val = + 1 ;
b - > description = VLC - > generaltexth - > arraytxt [ 115 ] ; //All troops of one alignment +1
}
2013-04-27 11:11:20 +03:00
else if ( factions . size ( ) ) // no bonus from empty garrison
2011-02-04 16:58:14 +02:00
{
2013-01-10 21:53:49 +03:00
b - > val = 2 - factionsInArmy ;
b - > description = boost : : str ( boost : : format ( VLC - > generaltexth - > arraytxt [ 114 ] ) % factionsInArmy % b - > val ) ; //Troops of %d alignments %d
2011-02-04 16:58:14 +02:00
}
2011-02-22 11:47:25 +02:00
boost : : algorithm : : trim ( b - > description ) ;
2012-07-19 21:52:44 +03:00
2013-01-10 21:53:49 +03:00
//-1 modifier for any Undead unit in army
2011-02-21 06:13:00 +02:00
const ui8 UNDEAD_MODIFIER_ID = - 2 ;
2011-07-13 21:39:02 +03:00
Bonus * undeadModifier = getBonusList ( ) . getFirst ( Selector : : source ( Bonus : : ARMY , UNDEAD_MODIFIER_ID ) ) ;
2013-01-10 21:53:49 +03:00
if ( hasUndead )
2011-02-21 06:13:00 +02:00
{
if ( ! undeadModifier )
addNewBonus ( new Bonus ( Bonus : : PERMANENT , Bonus : : MORALE , Bonus : : ARMY , - 1 , UNDEAD_MODIFIER_ID , VLC - > generaltexth - > arraytxt [ 116 ] ) ) ;
}
else if ( undeadModifier )
removeBonus ( undeadModifier ) ;
2012-07-19 21:52:44 +03:00
2011-02-04 16:58:14 +02:00
}
void CArmedInstance : : armyChanged ( )
{
updateMoraleBonusFromArmy ( ) ;
}
2011-02-22 11:47:25 +02:00
CBonusSystemNode * CArmedInstance : : whereShouldBeAttached ( CGameState * gs )
{
2013-03-03 20:06:03 +03:00
if ( tempOwner < PlayerColor : : PLAYER_LIMIT )
2011-02-22 11:47:25 +02:00
return gs - > getPlayer ( tempOwner ) ;
else
return & gs - > globalEffects ;
}
CBonusSystemNode * CArmedInstance : : whatShouldBeAttached ( )
{
return this ;
}
2011-12-14 00:23:17 +03:00
bool IMarket : : getOffer ( int id1 , int id2 , int & val1 , int & val2 , EMarketMode : : EMarketMode mode ) const
2010-05-18 10:01:54 +03:00
{
switch ( mode )
{
2011-12-14 00:23:17 +03:00
case EMarketMode : : RESOURCE_RESOURCE :
2010-05-18 10:01:54 +03:00
{
2011-12-14 00:23:17 +03:00
double effectiveness = std : : min ( ( getMarketEfficiency ( ) + 1.0 ) / 20.0 , 0.5 ) ;
2010-05-18 10:01:54 +03:00
2011-12-14 00:23:17 +03:00
double r = VLC - > objh - > resVals [ id1 ] , //value of given resource
2010-05-18 10:01:54 +03:00
g = VLC - > objh - > resVals [ id2 ] / effectiveness ; //value of wanted resource
if ( r > g ) //if given resource is more expensive than wanted
{
val2 = ceil ( r / g ) ;
val1 = 1 ;
}
else //if wanted resource is more expensive
{
2011-12-14 00:23:17 +03:00
val1 = ( g / r ) + 0.5 ;
2010-05-18 10:01:54 +03:00
val2 = 1 ;
}
}
2010-05-26 12:47:53 +03:00
break ;
2011-12-14 00:23:17 +03:00
case EMarketMode : : CREATURE_RESOURCE :
2010-05-26 12:47:53 +03:00
{
2011-12-14 00:23:17 +03:00
const double effectivenessArray [ ] = { 0.0 , 0.3 , 0.45 , 0.50 , 0.65 , 0.7 , 0.85 , 0.9 , 1.0 } ;
double effectiveness = effectivenessArray [ std : : min ( getMarketEfficiency ( ) , 8 ) ] ;
2010-05-26 12:47:53 +03:00
2011-12-14 00:23:17 +03:00
double r = VLC - > creh - > creatures [ id1 ] - > cost [ 6 ] , //value of given creature in gold
2010-05-26 12:47:53 +03:00
g = VLC - > objh - > resVals [ id2 ] / effectiveness ; //value of wanted resource
2010-05-18 10:01:54 +03:00
2010-05-26 12:47:53 +03:00
if ( r > g ) //if given resource is more expensive than wanted
{
val2 = ceil ( r / g ) ;
val1 = 1 ;
}
else //if wanted resource is more expensive
{
2011-12-14 00:23:17 +03:00
val1 = ( g / r ) + 0.5 ;
2010-05-26 12:47:53 +03:00
val2 = 1 ;
}
}
break ;
2011-12-14 00:23:17 +03:00
case EMarketMode : : RESOURCE_PLAYER :
2010-05-26 12:47:53 +03:00
val1 = 1 ;
val2 = 1 ;
2010-05-18 10:01:54 +03:00
break ;
2011-12-14 00:23:17 +03:00
case EMarketMode : : RESOURCE_ARTIFACT :
2010-06-27 19:03:01 +03:00
{
2011-12-14 00:23:17 +03:00
double effectiveness = std : : min ( ( getMarketEfficiency ( ) + 3.0 ) / 20.0 , 0.6 ) ;
double r = VLC - > objh - > resVals [ id1 ] , //value of offered resource
2010-06-27 19:03:01 +03:00
g = VLC - > arth - > artifacts [ id2 ] - > price / effectiveness ; //value of bought artifact in gold
2012-07-19 21:52:44 +03:00
2010-06-27 19:03:01 +03:00
if ( id1 ! = 6 ) //non-gold prices are doubled
2012-07-19 21:52:44 +03:00
r / = 2 ;
2010-06-27 19:03:01 +03:00
2012-01-28 14:42:15 +03:00
val1 = std : : max ( 1 , ( int ) ( ( g / r ) + 0.5 ) ) ; //don't sell arts for less than 1 resource
2010-06-27 19:03:01 +03:00
val2 = 1 ;
}
break ;
2011-12-14 00:23:17 +03:00
case EMarketMode : : ARTIFACT_RESOURCE :
2011-04-23 00:51:10 +03:00
{
2011-12-14 00:23:17 +03:00
double effectiveness = std : : min ( ( getMarketEfficiency ( ) + 3.0 ) / 20.0 , 0.6 ) ;
double r = VLC - > arth - > artifacts [ id1 ] - > price * effectiveness ,
2012-07-19 21:52:44 +03:00
g = VLC - > objh - > resVals [ id2 ] ;
2011-04-23 00:51:10 +03:00
// if(id2 != 6) //non-gold prices are doubled
2012-07-19 21:52:44 +03:00
// r /= 2;
2010-06-27 19:03:01 +03:00
2011-04-23 00:51:10 +03:00
val1 = 1 ;
2012-01-28 14:42:15 +03:00
val2 = std : : max ( 1 , ( int ) ( ( r / g ) + 0.5 ) ) ; //at least one resource is given in return
2011-04-23 00:51:10 +03:00
}
break ;
2011-12-14 00:23:17 +03:00
case EMarketMode : : CREATURE_EXP :
2010-07-20 09:05:45 +03:00
{
val1 = 1 ;
val2 = ( VLC - > creh - > creatures [ id1 ] - > AIValue / 40 ) * 5 ;
}
break ;
2011-12-14 00:23:17 +03:00
case EMarketMode : : ARTIFACT_EXP :
2010-07-23 15:02:15 +03:00
{
val1 = 1 ;
2010-07-20 09:05:45 +03:00
2010-07-23 15:02:15 +03:00
int givenClass = VLC - > arth - > artifacts [ id1 ] - > getArtClassSerial ( ) ;
if ( givenClass < 0 | | givenClass > 3 )
{
val2 = 0 ;
return false ;
}
static const int expPerClass [ ] = { 1000 , 1500 , 3000 , 6000 } ;
val2 = expPerClass [ givenClass ] ;
}
break ;
2010-05-18 10:01:54 +03:00
default :
assert ( 0 ) ;
return false ;
}
return true ;
}
2011-12-14 00:23:17 +03:00
bool IMarket : : allowsTrade ( EMarketMode : : EMarketMode mode ) const
2010-05-18 10:01:54 +03:00
{
return false ;
}
2011-12-14 00:23:17 +03:00
int IMarket : : availableUnits ( EMarketMode : : EMarketMode mode , int marketItemSerial ) const
2010-05-18 10:01:54 +03:00
{
2010-05-26 12:47:53 +03:00
switch ( mode )
{
2011-12-14 00:23:17 +03:00
case EMarketMode : : RESOURCE_RESOURCE :
case EMarketMode : : ARTIFACT_RESOURCE :
case EMarketMode : : CREATURE_RESOURCE :
2010-05-26 12:47:53 +03:00
return - 1 ;
default :
return 1 ;
}
2010-05-18 10:01:54 +03:00
}
2011-12-14 00:23:17 +03:00
std : : vector < int > IMarket : : availableItemsIds ( EMarketMode : : EMarketMode mode ) const
2010-05-18 10:01:54 +03:00
{
std : : vector < int > ret ;
2010-05-26 12:47:53 +03:00
switch ( mode )
{
2011-12-14 00:23:17 +03:00
case EMarketMode : : RESOURCE_RESOURCE :
case EMarketMode : : ARTIFACT_RESOURCE :
case EMarketMode : : CREATURE_RESOURCE :
2010-05-18 10:01:54 +03:00
for ( int i = 0 ; i < 7 ; i + + )
ret . push_back ( i ) ;
2010-08-30 02:12:34 +03:00
default :
2010-05-26 12:47:53 +03:00
break ;
}
2010-05-18 10:01:54 +03:00
return ret ;
}
2012-02-14 21:04:45 +03:00
const IMarket * IMarket : : castFrom ( const CGObjectInstance * obj , bool verbose /*= true*/ )
2010-05-18 10:01:54 +03:00
{
switch ( obj - > ID )
{
2012-09-23 21:01:04 +03:00
case Obj : : TOWN :
2010-05-18 10:01:54 +03:00
return static_cast < const CGTownInstance * > ( obj ) ;
2012-09-23 21:01:04 +03:00
case Obj : : ALTAR_OF_SACRIFICE :
case Obj : : BLACK_MARKET :
case Obj : : TRADING_POST :
case Obj : : TRADING_POST_SNOW :
case Obj : : FREELANCERS_GUILD :
2010-05-18 10:01:54 +03:00
return static_cast < const CGMarket * > ( obj ) ;
2012-09-23 21:01:04 +03:00
case Obj : : UNIVERSITY :
2010-07-20 17:08:13 +03:00
return static_cast < const CGUniversity * > ( obj ) ;
2010-05-18 10:01:54 +03:00
default :
2012-02-14 21:04:45 +03:00
if ( verbose )
2013-04-09 17:31:36 +03:00
logGlobal - > errorStream ( ) < < " Cannot cast to IMarket object with ID " < < obj - > ID ;
2013-06-26 14:18:27 +03:00
return nullptr ;
2010-05-18 10:01:54 +03:00
}
}
IMarket : : IMarket ( const CGObjectInstance * O )
: o ( O )
{
}
2011-12-14 00:23:17 +03:00
std : : vector < EMarketMode : : EMarketMode > IMarket : : availableModes ( ) const
2010-05-18 10:01:54 +03:00
{
2011-12-14 00:23:17 +03:00
std : : vector < EMarketMode : : EMarketMode > ret ;
for ( int i = 0 ; i < EMarketMode : : MARTKET_AFTER_LAST_PLACEHOLDER ; i + + )
if ( allowsTrade ( ( EMarketMode : : EMarketMode ) i ) )
ret . push_back ( ( EMarketMode : : EMarketMode ) i ) ;
2010-05-18 10:01:54 +03:00
return ret ;
}
void CGMarket : : onHeroVisit ( const CGHeroInstance * h ) const
{
2013-02-14 02:55:42 +03:00
openWindow ( OpenWindow : : MARKET_WINDOW , id . getNum ( ) , h - > id . getNum ( ) ) ;
2010-05-18 10:01:54 +03:00
}
int CGMarket : : getMarketEfficiency ( ) const
{
return 5 ;
}
2011-12-14 00:23:17 +03:00
bool CGMarket : : allowsTrade ( EMarketMode : : EMarketMode mode ) const
2010-05-18 10:01:54 +03:00
{
switch ( mode )
{
2011-12-14 00:23:17 +03:00
case EMarketMode : : RESOURCE_RESOURCE :
case EMarketMode : : RESOURCE_PLAYER :
2010-05-18 10:01:54 +03:00
switch ( ID )
{
2012-09-23 21:01:04 +03:00
case Obj : : TRADING_POST :
case Obj : : TRADING_POST_SNOW :
2010-05-18 10:01:54 +03:00
return true ;
default :
return false ;
}
2011-12-14 00:23:17 +03:00
case EMarketMode : : CREATURE_RESOURCE :
2012-09-23 21:01:04 +03:00
return ID = = Obj : : FREELANCERS_GUILD ;
2010-07-26 18:37:58 +03:00
//case ARTIFACT_RESOURCE:
2011-12-14 00:23:17 +03:00
case EMarketMode : : RESOURCE_ARTIFACT :
2012-09-23 21:01:04 +03:00
return ID = = Obj : : BLACK_MARKET ;
2011-12-14 00:23:17 +03:00
case EMarketMode : : ARTIFACT_EXP :
case EMarketMode : : CREATURE_EXP :
2012-09-23 21:01:04 +03:00
return ID = = Obj : : ALTAR_OF_SACRIFICE ; //TODO? check here for alignment of visiting hero? - would not be coherent with other checks here
2011-12-14 00:23:17 +03:00
case EMarketMode : : RESOURCE_SKILL :
2012-09-23 21:01:04 +03:00
return ID = = Obj : : UNIVERSITY ;
2010-08-30 02:12:34 +03:00
default :
return false ;
2010-05-18 10:01:54 +03:00
}
}
2011-12-14 00:23:17 +03:00
int CGMarket : : availableUnits ( EMarketMode : : EMarketMode mode , int marketItemSerial ) const
2010-05-18 10:01:54 +03:00
{
return - 1 ;
}
2011-12-14 00:23:17 +03:00
std : : vector < int > CGMarket : : availableItemsIds ( EMarketMode : : EMarketMode mode ) const
2010-05-18 10:01:54 +03:00
{
switch ( mode )
{
2011-12-14 00:23:17 +03:00
case EMarketMode : : RESOURCE_RESOURCE :
case EMarketMode : : RESOURCE_PLAYER :
2010-05-18 10:01:54 +03:00
return IMarket : : availableItemsIds ( mode ) ;
default :
return std : : vector < int > ( ) ;
}
}
CGMarket : : CGMarket ( )
: IMarket ( this )
{
2010-06-26 19:02:10 +03:00
}
2011-12-14 00:23:17 +03:00
std : : vector < int > CGBlackMarket : : availableItemsIds ( EMarketMode : : EMarketMode mode ) const
2010-06-26 19:02:10 +03:00
{
switch ( mode )
{
2011-12-14 00:23:17 +03:00
case EMarketMode : : ARTIFACT_RESOURCE :
2010-06-26 19:02:10 +03:00
return IMarket : : availableItemsIds ( mode ) ;
2011-12-14 00:23:17 +03:00
case EMarketMode : : RESOURCE_ARTIFACT :
2010-06-26 19:02:10 +03:00
{
std : : vector < int > ret ;
2013-06-29 16:05:48 +03:00
for ( const CArtifact * a : artifacts )
2010-06-26 19:02:10 +03:00
if ( a )
ret . push_back ( a - > id ) ;
else
ret . push_back ( - 1 ) ;
return ret ;
}
default :
return std : : vector < int > ( ) ;
}
}
void CGBlackMarket : : newTurn ( ) const
{
2013-02-02 11:29:57 +03:00
if ( cb - > getDate ( Date : : DAY_OF_MONTH ) ! = 1 ) //new month
2010-06-27 19:03:01 +03:00
return ;
2010-06-26 19:02:10 +03:00
2010-06-27 19:03:01 +03:00
SetAvailableArtifacts saa ;
2013-02-14 02:55:42 +03:00
saa . id = id . getNum ( ) ;
2010-06-27 19:03:01 +03:00
cb - > pickAllowedArtsSet ( saa . arts ) ;
cb - > sendAndApply ( & saa ) ;
2010-07-20 17:08:13 +03:00
}
void CGUniversity : : initObj ( )
{
std : : vector < int > toChoose ;
2011-12-14 00:23:17 +03:00
for ( int i = 0 ; i < GameConstants : : SKILL_QUANTITY ; i + + )
2010-07-20 17:08:13 +03:00
if ( cb - > isAllowed ( 2 , i ) )
toChoose . push_back ( i ) ;
if ( toChoose . size ( ) < 4 )
{
2013-04-09 17:31:36 +03:00
logGlobal - > warnStream ( ) < < " Warning: less then 4 available skills was found by University initializer! " ;
2010-07-20 17:08:13 +03:00
return ;
}
2012-07-19 21:52:44 +03:00
2010-07-20 17:08:13 +03:00
for ( int i = 0 ; i < 4 ; i + + ) //get 4 skills
{
int skillPos = ran ( ) % toChoose . size ( ) ;
skills . push_back ( toChoose [ skillPos ] ) ; //move it to selected
toChoose . erase ( toChoose . begin ( ) + skillPos ) ; //remove from list
}
}
2011-12-14 00:23:17 +03:00
std : : vector < int > CGUniversity : : availableItemsIds ( EMarketMode : : EMarketMode mode ) const
2010-07-20 17:08:13 +03:00
{
switch ( mode )
{
2011-12-14 00:23:17 +03:00
case EMarketMode : : RESOURCE_SKILL :
2010-07-20 17:08:13 +03:00
return skills ;
2012-07-19 21:52:44 +03:00
2010-07-20 17:08:13 +03:00
default :
return std : : vector < int > ( ) ;
}
}
void CGUniversity : : onHeroVisit ( const CGHeroInstance * h ) const
{
2013-02-14 02:55:42 +03:00
openWindow ( OpenWindow : : UNIVERSITY_WINDOW , id . getNum ( ) , h - > id . getNum ( ) ) ;
2010-07-20 17:08:13 +03:00
}
2011-08-26 23:32:05 +03:00
GrowthInfo : : Entry : : Entry ( const std : : string & format , int _count )
: count ( _count )
{
description = boost : : str ( boost : : format ( format ) % count ) ;
}
2013-02-11 02:24:57 +03:00
GrowthInfo : : Entry : : Entry ( int subID , BuildingID building , int _count )
2011-08-26 23:32:05 +03:00
: count ( _count )
{
2013-04-21 15:49:26 +03:00
description = boost : : str ( boost : : format ( " %s %+d " ) % VLC - > townh - > factions [ subID ] - > town - > buildings [ building ] - > Name ( ) % count ) ;
2011-08-26 23:32:05 +03:00
}
CTownAndVisitingHero : : CTownAndVisitingHero ( )
{
setNodeType ( TOWN_AND_VISITOR ) ;
}
int GrowthInfo : : totalGrowth ( ) const
{
int ret = 0 ;
2013-06-29 16:05:48 +03:00
for ( const Entry & entry : entries )
2011-08-26 23:32:05 +03:00
ret + = entry . count ;
return ret ;
2011-09-03 17:14:43 +03:00
}