2008-06-17 20:48:32 +03:00
# define VCMI_DLL
2008-01-09 19:21:31 +02:00
# include "../stdafx.h"
2007-06-12 12:33:20 +03:00
# include "CObjectHandler.h"
2008-06-13 11:16:51 +03:00
# include "CDefObjInfoHandler.h"
2007-08-29 15:18:31 +03:00
# include "CLodHandler.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"
2008-12-22 19:48:41 +02:00
# include <boost/bind.hpp>
2007-11-24 00:33:55 +02:00
# include <boost/algorithm/string/replace.hpp>
2009-07-26 06:33:13 +03:00
# include <boost/assign/std/vector.hpp>
2009-02-05 11:49:45 +02:00
# include <boost/lexical_cast.hpp>
2008-10-26 22:58:34 +02:00
# include <boost/random/linear_congruential.hpp>
2008-04-14 20:45:01 +03:00
# include "CTownHandler.h"
2008-06-08 03:58:29 +03:00
# include "CArtHandler.h"
2009-04-22 21:48:56 +03:00
# include "CSoundBase.h"
2010-07-16 17:22:18 +03:00
# include "CCreatureHandler.h"
2008-06-17 20:48:32 +03:00
# include "../lib/VCMI_Lib.h"
2008-12-22 19:48:41 +02:00
# include "../lib/IGameCallback.h"
2009-05-20 13:08:56 +03:00
# include "../lib/CGameState.h"
2008-12-22 19:48:41 +02:00
# include "../lib/NetPacks.h"
2009-02-08 08:42:15 +02:00
# include "../StartInfo.h"
2009-05-20 13:08:56 +03:00
# include "../lib/map.h"
2009-08-20 13:07:23 +03:00
# include <sstream>
2009-09-17 13:47:47 +03:00
# include <SDL_stdinc.h>
2010-03-21 00:17:19 +02:00
# include <boost/foreach.hpp>
2010-05-02 21:20:26 +03:00
# include <boost/format.hpp>
2009-07-26 06:33:13 +03:00
using namespace boost : : assign ;
2008-12-22 19:48:41 +02:00
2009-04-15 17:03:31 +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
*
*/
2008-12-27 03:01:59 +02:00
std : : map < int , std : : map < int , std : : vector < int > > > CGTeleport : : objs ;
2009-09-07 05:29:44 +03:00
std : : vector < std : : pair < int , int > > CGTeleport : : gates ;
2008-12-22 19:48:41 +02:00
IGameCallback * IObjectInterface : : cb = NULL ;
2010-02-12 17:04:01 +02:00
DLL_EXPORT void loadToIt ( std : : string & dest , const std : : string & src , int & iter , int mode ) ;
2008-06-17 20:48:32 +03:00
extern CLodHandler * bitmaph ;
2008-10-26 22:58:34 +02:00
extern boost : : rand48 ran ;
2009-08-11 10:50:29 +03:00
std : : map < ui8 , std : : set < ui8 > > CGKeys : : playerKeyMap ;
2009-08-13 04:03:11 +03:00
std : : map < si32 , std : : vector < si32 > > CGMagi : : eyelist ;
2009-09-24 20:54:02 +03:00
BankConfig CGPyramid : : pyramidConfig ;
2010-02-10 04:56:00 +02:00
ui8 CGObelisk : : obeliskCount ; //how many obelisks are on map
std : : map < ui8 , ui8 > CGObelisk : : visited ; //map: color_id => how many obelisks has been visited
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
2008-12-27 03:01:59 +02:00
void IObjectInterface : : onHeroVisit ( const CGHeroInstance * h ) const
2008-12-22 19:48:41 +02:00
{ } ;
2008-12-27 03:01:59 +02:00
void IObjectInterface : : onHeroLeave ( const CGHeroInstance * h ) const
2008-12-22 19:48:41 +02:00
{ } ;
2008-12-27 03:01:59 +02:00
void IObjectInterface : : newTurn ( ) const
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 )
{ }
2009-09-07 05:29:44 +03:00
void IObjectInterface : : postInit ( )
{ }
void IObjectInterface : : preInit ( )
{ }
2009-03-14 19:19:53 +02:00
void CPlayersVisited : : setPropertyDer ( ui8 what , ui32 val )
{
if ( what = = 10 )
2010-05-26 12:47:53 +03:00
players . insert ( ( ui8 ) val ) ;
2009-03-14 19:19:53 +02:00
}
bool CPlayersVisited : : hasVisited ( ui8 player ) const
{
return vstd : : contains ( players , player ) ;
}
2009-08-20 13:07:23 +03:00
static void readCreatures ( std : : istream & is , BankConfig & bc , bool guards ) //helper function for void CObjectHandler::loadObjects()
{
const int MAX_BUF = 5000 ;
char buffer [ MAX_BUF + 1 ] ;
std : : pair < si16 , si32 > guardInfo = std : : make_pair ( 0 , 0 ) ;
std : : string creName ;
2009-08-29 19:08:58 +03:00
is > > guardInfo . second ;
2009-08-20 13:07:23 +03:00
//one getline just does not work... probably a kind of left whitespace
is . getline ( buffer , MAX_BUF , ' \t ' ) ;
is . getline ( buffer , MAX_BUF , ' \t ' ) ;
creName = buffer ;
if ( std : : string ( buffer ) = = " None " ) //no creature to be added
return ;
//look for the best creature that is described by given name
if ( vstd : : contains ( VLC - > creh - > nameToID , creName ) )
{
2009-08-29 19:08:58 +03:00
guardInfo . first = VLC - > creh - > nameToID [ creName ] ;
2009-08-20 13:07:23 +03:00
}
else
{
for ( int g = 0 ; g < VLC - > creh - > creatures . size ( ) ; + + g )
{
2010-05-02 21:20:26 +03:00
if ( VLC - > creh - > creatures [ g ] - > namePl = = creName
| | VLC - > creh - > creatures [ g ] - > nameRef = = creName
| | VLC - > creh - > creatures [ g ] - > nameSing = = creName )
2009-08-20 13:07:23 +03:00
{
2010-05-02 21:20:26 +03:00
guardInfo . first = VLC - > creh - > creatures [ g ] - > idNumber ;
2009-08-20 13:07:23 +03:00
}
}
}
if ( guards )
bc . guards . push_back ( guardInfo ) ;
else //given creatures
bc . creatures . push_back ( guardInfo ) ;
}
2007-06-11 20:21:27 +03:00
void CObjectHandler : : loadObjects ( )
{
2008-02-05 05:56:45 +02:00
{
2009-08-13 04:03:11 +03:00
tlog5 < < " \t \t Reading cregens \n " ;
cregens . resize ( 110 ) ; //TODO: hardcoded value - change
for ( size_t i = 0 ; i < cregens . size ( ) ; + + i )
{
cregens [ i ] = - 1 ;
}
2009-10-04 05:02:45 +03:00
std : : ifstream ifs ( DATA_DIR " /config/cregens.txt " ) ;
2009-08-13 04:03:11 +03:00
while ( ! ifs . eof ( ) )
{
int dw , cr ;
ifs > > dw > > cr ;
cregens [ dw ] = cr ;
}
tlog5 < < " \t \t Done loading objects! \n " ;
2010-05-18 10:01:54 +03:00
ifs . close ( ) ;
ifs . clear ( ) ;
int k = - 1 ;
ifs . open ( DATA_DIR " /config/resources.txt " ) ;
ifs > > k ;
int pom ;
for ( int i = 0 ; i < k ; i + + )
{
ifs > > pom ;
resVals . push_back ( pom ) ;
}
tlog5 < < " \t \t Done loading resource prices! \n " ;
2008-02-05 05:56:45 +02:00
}
2009-08-13 04:03:11 +03:00
2010-05-18 10:01:54 +03:00
2009-09-25 12:57:13 +03:00
std : : ifstream istr ;
2009-10-04 05:02:45 +03:00
istr . open ( DATA_DIR " /config/bankconfig.txt " , std : : ios_base : : binary ) ;
2009-09-25 12:57:13 +03:00
if ( ! istr . is_open ( ) )
{
tlog1 < < " No config/bankconfig.txt file !!! \n " ;
}
2009-08-20 13:07:23 +03:00
const int MAX_BUF = 5000 ;
char buffer [ MAX_BUF + 1 ] ;
//omitting unnecessary lines
istr . getline ( buffer , MAX_BUF ) ;
istr . getline ( buffer , MAX_BUF ) ;
2009-08-18 11:22:56 +03:00
2009-08-20 13:07:23 +03:00
for ( int g = 0 ; g < 21 ; + + g ) //TODO: remove hardcoded value
{
2009-09-17 14:05:50 +03:00
//reading name
2009-08-20 13:07:23 +03:00
istr . getline ( buffer , MAX_BUF , ' \t ' ) ;
2009-09-17 14:05:50 +03:00
creBanksNames [ g ] = std : : string ( buffer ) ;
//remove trailing new line characters
while ( creBanksNames [ g ] [ 0 ] = = 10 | | creBanksNames [ g ] [ 0 ] = = 13 )
creBanksNames [ g ] . erase ( creBanksNames [ g ] . begin ( ) ) ;
2009-08-20 13:07:23 +03:00
for ( int i = 0 ; i < 4 ; + + i ) //reading levels
{
2009-12-29 03:07:17 +02:00
banksInfo [ g ] . push_back ( new BankConfig ) ;
BankConfig & bc = * banksInfo [ g ] . back ( ) ;
2009-08-20 13:07:23 +03:00
std : : string buf ;
char dump ;
//bc.level is of type char and thus we cannot read directly to it; same for some othre variables
istr > > buf ;
bc . level = atoi ( buf . c_str ( ) ) ;
istr > > buf ;
bc . chance = atoi ( buf . c_str ( ) ) ;
readCreatures ( istr , bc , true ) ;
istr > > buf ;
bc . upgradeChance = atoi ( buf . c_str ( ) ) ;
for ( int b = 0 ; b < 3 ; + + b )
readCreatures ( istr , bc , true ) ;
istr > > bc . combatValue ;
bc . resources . resize ( RESOURCE_QUANTITY ) ;
2009-09-17 13:47:47 +03:00
//a dirty trick to make it work if there is no 0 for 0 quantity (like in grotto - last entry)
char buft [ 52 ] ;
istr . getline ( buft , 50 , ' \t ' ) ;
2009-08-20 13:07:23 +03:00
for ( int h = 0 ; h < 7 ; + + h )
{
2009-09-17 13:47:47 +03:00
istr . getline ( buft , 50 , ' \t ' ) ;
if ( buft [ 0 ] = = ' \0 ' )
bc . resources [ h ] = 0 ;
else
bc . resources [ h ] = SDL_atoi ( buft ) ;
2009-08-20 13:07:23 +03:00
}
readCreatures ( istr , bc , false ) ;
bc . artifacts . resize ( 4 ) ;
for ( int b = 0 ; b < 4 ; + + b )
{
istr > > bc . artifacts [ b ] ;
}
istr > > bc . value ;
istr > > bc . rewardDifficulty ;
istr > > buf ;
bc . easiest = atoi ( buf . c_str ( ) ) ;
}
}
2007-08-09 19:28:01 +03:00
}
2009-08-20 13:07:23 +03:00
2007-10-27 22:38:48 +03:00
int CGObjectInstance : : getOwner ( ) const
{
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
}
2008-12-22 19:48:41 +02:00
CGObjectInstance : : CGObjectInstance ( ) : animPhaseShift ( rand ( ) % 0xff )
{
pos = int3 ( - 1 , - 1 , - 1 ) ;
//std::cout << "Tworze obiekt "<<this<<std::endl;
//state = new CLuaObjectScript();
ID = subID = id = - 1 ;
defInfo = NULL ;
tempOwner = 254 ;
blockVisit = false ;
}
CGObjectInstance : : ~ CGObjectInstance ( )
{
//std::cout << "Usuwam obiekt "<<this<<std::endl;
//if (state)
// delete state;
//state=NULL;
}
2008-12-31 11:33:46 +02:00
//CGObjectInstance::CGObjectInstance(const CGObjectInstance & right)
//{
// pos = right.pos;
// ID = right.ID;
// subID = right.subID;
// id = right.id;
// defInfo = right.defInfo;
// info = right.info;
// blockVisit = right.blockVisit;
// //state = new CLuaObjectScript(right.state->);
// //*state = *right.state;
// //state = right.state;
// tempOwner = right.tempOwner;
//}
//CGObjectInstance& CGObjectInstance::operator=(const CGObjectInstance & right)
//{
// pos = right.pos;
// ID = right.ID;
// subID = right.subID;
// id = right.id;
// defInfo = right.defInfo;
// info = right.info;
// blockVisit = right.blockVisit;
// //state = new CLuaObjectScript();
// //*state = *right.state;
// tempOwner = right.tempOwner;
// return *this;
//}
2008-12-22 19:48:41 +02:00
const std : : string & CGObjectInstance : : getHoverText ( ) const
{
return hoverName ;
}
2007-11-19 00:58:28 +02:00
void CGObjectInstance : : setOwner ( int ow )
{
//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
{
2009-03-12 01:25:59 +02:00
if ( defInfo = = NULL )
{
tlog2 < < " Warning: VisitableAt for obj " < < id < < " : NULL defInfo! \n " ;
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
{
if ( x < 0 | | y < 0 | | x > = getWidth ( ) | | y > = getHeight ( ) | | defInfo = = NULL )
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
{
2009-12-22 23:53:50 +02:00
if ( ( defInfo - > coverageMap [ y ] > > ( 7 - ( x ) ) ) & 1
| | ( defInfo - > shadowCoverage [ y ] > > ( 7 - ( x ) ) ) & 1 )
2009-07-01 18:58:20 +03:00
return true ;
return false ;
}
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 ;
2009-02-06 16:15:45 +02:00
if ( cmp . ID = = HEROI_TYPE & & ID ! = HEROI_TYPE )
2008-02-23 21:20:41 +02:00
return true ;
2009-02-06 16:15:45 +02:00
if ( cmp . ID ! = HEROI_TYPE & & ID = = HEROI_TYPE )
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 )
{
case 95 :
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 :
2009-02-20 14:39:27 +02:00
tempOwner = val ;
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 :
2009-02-20 14:39:27 +02:00
ID = val ;
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 ;
}
2009-11-11 19:45:03 +02:00
void CGObjectInstance : : getSightTiles ( std : : set < int3 > & tiles ) const //returns reference to the set
{
2009-12-01 12:23:23 +02:00
cb - > getTilesInRange ( tiles , getSightCenter ( ) , getSightRadious ( ) , tempOwner , 1 ) ;
2009-11-11 19:45:03 +02:00
}
2010-06-19 12:13:10 +03:00
void CGObjectInstance : : hideTiles ( int ourplayer , int radius ) const
{
2010-08-03 15:34:06 +03:00
for ( std : : map < ui8 , TeamState > : : iterator i = cb - > gameState ( ) - > teams . begin ( ) ; i ! = cb - > gameState ( ) - > teams . end ( ) ; i + + )
2010-06-19 12:13:10 +03:00
{
2010-08-03 15:34:06 +03:00
if ( ! vstd : : contains ( i - > second . players , ourplayer ) /* && i->second.status == PlayerState::INGAME*/ )
2010-06-19 12:13:10 +03:00
{
FoWChange fw ;
fw . mode = 0 ;
fw . player = i - > first ;
cb - > getTilesInRange ( fw . tiles , pos , radius , i - > first , - 1 ) ;
cb - > sendAndApply ( & fw ) ;
}
}
}
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 ) ;
tlog2 < < " Warning: getVisitableOffset called on non-visitable obj! \n " ;
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 ] ;
if ( h )
{
2010-05-02 21:20:26 +03:00
if ( ! h - > hasBonusFrom ( Bonus : : OBJECT , ID ) )
2009-07-19 10:16:33 +03:00
hname + = " " + VLC - > generaltexth - > allTexts [ 353 ] ; //not visited
else
hname + = " " + VLC - > generaltexth - > allTexts [ 352 ] ; //visited
}
}
void CGObjectInstance : : giveDummyBonus ( int heroID , ui8 duration ) const
{
GiveBonus gbonus ;
2010-05-02 21:20:26 +03:00
gbonus . bonus . type = Bonus : : NONE ;
2010-02-10 04:56:00 +02:00
gbonus . id = heroID ;
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 ;
2009-07-19 10:16:33 +03:00
gbonus . bonus . id = ID ;
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 )
{
2010-07-22 03:32:45 +03:00
case 35 : //Hill fort
{
OpenWindow ow ;
ow . window = OpenWindow : : HILL_FORT_WINDOW ;
ow . id1 = id ;
ow . id2 = h - > id ;
cb - > sendAndApply ( & ow ) ;
}
break ;
2010-07-09 03:54:17 +03:00
case 80 : //Sanctuary
{
InfoWindow iw ;
iw . player = h - > tempOwner ;
iw . soundID = soundBase : : GETPROTECTION ;
iw . text . addTxt ( MetaString : : ADVOB_TXT , 114 ) ; //You enter the sanctuary and immediately feel as if a great weight has been lifted off your shoulders. You feel safe here.
cb - > sendAndApply ( & iw ) ;
}
break ;
case 95 : //Tavern
{
OpenWindow ow ;
ow . window = OpenWindow : : TAVERN_WINDOW ;
ow . id1 = h - > id ;
ow . id2 = id ;
cb - > sendAndApply ( & ow ) ;
}
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-02-21 20:07:24 +02:00
bool CGObjectInstance : : hasShadowAt ( int x , int y ) const
{
if ( ( defInfo - > shadowCoverage [ y ] > > ( 7 - ( x ) ) ) & 1 )
return true ;
return false ;
}
2010-05-15 11:33:32 +03:00
int3 CGObjectInstance : : visitablePos ( ) const
{
return pos - getVisitableOffset ( ) ;
}
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
{
tlog1 < < " Error! Hero " < < chi - > id < < " ( " < < chi - > name < < " ) has no army! \n " ;
return 20 ;
}
2010-05-02 21:20:26 +03:00
TSlots : : const_iterator i = chi - > Slots ( ) . begin ( ) ;
//TODO? should speed modifiers (eg from artifacts) affect hero movement?
int ret = ( i + + ) - > second . valOfBonuses ( Bonus : : STACKS_SPEED ) ;
for ( ; i ! = chi - > Slots ( ) . end ( ) ; i + + )
2008-12-22 19:48:41 +02:00
{
2010-05-02 21:20:26 +03: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
2009-02-12 16:44:58 +02:00
unsigned int 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
//TODO: check if all creatures are on its native terrain and change cost appropriately
//base move cost
unsigned ret = 100 ;
//if there is road both on dest and src tiles - use road movement cost
if ( dest . malle & & from . malle )
2008-09-28 16:29:37 +03:00
{
2009-02-12 16:44:58 +02:00
int road = std : : min ( dest . malle , from . malle ) ; //used road ID
switch ( road )
2008-09-28 16:29:37 +03:00
{
2009-05-07 20:20:41 +03:00
case TerrainTile : : dirtRoad :
2009-02-12 16:44:58 +02:00
ret = 75 ;
2008-09-28 16:29:37 +03:00
break ;
2009-05-07 20:20:41 +03:00
case TerrainTile : : grazvelRoad :
2009-02-12 16:44:58 +02:00
ret = 65 ;
2008-09-28 16:29:37 +03:00
break ;
2009-05-07 20:20:41 +03:00
case TerrainTile : : cobblestoneRoad :
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 :
tlog1 < < " Unknown road type: " < < road < < " ... Something wrong! \n " ;
2008-09-28 16:29:37 +03:00
break ;
}
}
2009-02-12 16:44:58 +02:00
else
2007-10-27 22:38:48 +03:00
{
2009-08-28 12:03:58 +03:00
ret = type - > heroClass - > terrCosts [ from . tertype ] ;
2009-02-12 16:44:58 +02:00
ret = std : : max ( ret - 25 * unsigned ( getSecSkillLevel ( 0 ) ) , 100u ) ; //reduce 25% of terrain penalty for each pathfinding level
2007-10-27 22:38:48 +03:00
}
return ret ;
}
2009-10-24 06:51:14 +03:00
#if 0
// Unused and buggy method.
// - for loop is wrong. will not find all creatures. must use iterator instead.
// - -> is the slot number. use second->first for creature index
// Is lowestSpeed() the correct equivalent ?
2008-12-22 19:48:41 +02:00
unsigned int CGHeroInstance : : getLowestCreatureSpeed ( ) const
2007-10-26 20:55:33 +03:00
{
2007-10-27 22:38:48 +03:00
unsigned int sl = 100 ;
2010-05-02 21:20:26 +03:00
for ( size_t h = 0 ; h < stacksCount ( ) ; + + h )
2007-10-27 22:38:48 +03:00
{
2010-05-02 21:20:26 +03:00
if ( VLC - > creh - > creatures [ Slots ( ) . find ( h ) - > first ] - > speed < sl )
sl = VLC - > creh - > creatures [ Slots ( ) . find ( h ) - > first ] - > speed ;
2007-10-27 22:38:48 +03:00
}
return sl ;
}
2009-10-24 06:51:14 +03:00
# endif
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
2008-12-31 11:33:46 +02:00
si32 CGHeroInstance : : manaLimit ( ) const
2007-10-27 22:38:48 +03:00
{
2010-07-21 20:05:07 +03:00
return si32 ( getPrimSkillLevel ( 3 ) * ( 100.0f + valOfBonuses ( Bonus : : SECONDARY_SKILL_PREMY , 24 ) ) / 10.0f ) ;
2007-10-26 20:55:33 +03:00
}
2008-10-18 14:41:24 +03:00
//void CGHeroInstance::setPosition(int3 Pos, bool h3m) //as above, but sets position
//{
// if (h3m)
// pos = Pos;
// else
// pos = convertPosition(Pos,true);
//}
2007-10-26 20:55:33 +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
2008-09-29 14:03:30 +03:00
int CGHeroInstance : : getPrimSkillLevel ( int id ) const
{
2010-05-02 21:20:26 +03:00
int ret = valOfBonuses ( Bonus : : PRIMARY_SKILL , id ) ;
2010-02-10 04:56:00 +02:00
amax ( ret , id / 2 ) ; //minimal value is 0 for attack and defense and 1 for spell power and knowledge
2009-04-04 01:34:31 +03:00
return ret ;
2008-09-29 14:03:30 +03:00
}
2010-05-15 18:00:19 +03:00
2008-12-31 11:33:46 +02:00
ui8 CGHeroInstance : : getSecSkillLevel ( const int & ID ) const
2008-02-25 01:06:27 +02:00
{
2008-12-21 21:17:35 +02:00
for ( size_t i = 0 ; i < secSkills . size ( ) ; + + i )
2008-02-25 01:06:27 +02:00
if ( secSkills [ i ] . first = = ID )
return secSkills [ i ] . 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
void CGHeroInstance : : setSecSkillLevel ( int which , int val , bool abs )
{
if ( getSecSkillLevel ( which ) = = 0 )
{
secSkills . push_back ( std : : pair < int , int > ( which , val ) ) ;
updateSkill ( which , val ) ;
}
else
{
for ( unsigned i = 0 ; i < secSkills . size ( ) ; i + + )
{
if ( secSkills [ i ] . first = = which )
{
if ( abs )
secSkills [ i ] . second = val ;
else
secSkills [ i ] . second + = val ;
if ( secSkills [ i ] . second > 3 ) //workaround to avoid crashes when same sec skill is given more than once
{
tlog1 < < " Warning: Skill " < < which < < " increased over limit! Decreasing to Expert. \n " ;
secSkills [ i ] . second = 3 ;
}
updateSkill ( which , secSkills [ i ] . second ) ; //when we know final value
}
}
}
}
2008-10-26 22:58:34 +02:00
int CGHeroInstance : : maxMovePoints ( bool onLand ) const
{
2010-02-10 04:56:00 +02:00
int base = - 1 ;
if ( onLand )
{
static const int moveForSpeed [ ] = { 1500 , 1560 , 1630 , 1700 , 1760 , 1830 , 1900 , 1960 , 2000 } ; //first element for 3 and lower; last for 11 and more
int index = lowestSpeed ( this ) - 3 ;
amin ( index , ARRAY_COUNT ( moveForSpeed ) - 1 ) ;
amax ( index , 0 ) ;
base = moveForSpeed [ index ] ;
}
else
{
base = 1500 ; //on water base movement is always 1500 (speed of army doesn't matter)
}
2010-05-02 21:20:26 +03:00
int bonus = valOfBonuses ( Bonus : : MOVEMENT ) + ( onLand ? valOfBonuses ( Bonus : : LAND_MOVEMENT ) : valOfBonuses ( Bonus : : SEA_MOVEMENT ) ) ;
2008-10-26 22:58:34 +02:00
2009-04-04 01:34:31 +03:00
double modifier = 0 ;
2008-10-26 22:58:34 +02:00
if ( onLand )
{
//logistics:
2010-07-17 20:02:11 +03:00
modifier = valOfBonuses ( Bonus : : SECONDARY_SKILL_PREMY , 2 ) / 100.0f ;
2008-10-26 22:58:34 +02:00
}
else
{
//navigation:
2010-07-17 20:02:11 +03:00
modifier = valOfBonuses ( Bonus : : SECONDARY_SKILL_PREMY , 5 ) / 100.0f ;
2008-10-26 22:58:34 +02:00
}
2010-02-10 04:56:00 +02:00
return int ( base + base * modifier ) + bonus ;
2008-10-26 22:58:34 +02:00
}
2009-04-04 01:34:31 +03:00
2008-08-20 22:02:48 +03:00
ui32 CGHeroInstance : : getArtAtPos ( ui16 pos ) const
{
if ( pos < 19 )
if ( vstd : : contains ( artifWorn , pos ) )
return artifWorn . find ( pos ) - > second ;
else
return - 1 ;
else
if ( pos - 19 < artifacts . size ( ) )
return artifacts [ pos - 19 ] ;
else
return - 1 ;
}
2009-04-04 01:34:31 +03:00
2008-09-28 16:29:37 +03:00
const CArtifact * CGHeroInstance : : getArt ( int pos ) const
2008-06-08 03:58:29 +03:00
{
2008-08-20 22:02:48 +03:00
int id = getArtAtPos ( pos ) ;
if ( id > = 0 )
2010-06-26 19:02:10 +03:00
return VLC - > arth - > artifacts [ id ] ;
2008-08-20 22:02:48 +03:00
else
2008-06-11 04:53:57 +03:00
return NULL ;
2008-06-08 03:58:29 +03:00
}
2008-11-11 17:17:58 +02:00
2010-07-28 13:09:15 +03:00
// int CGHeroInstance::getSpellSecLevel(int spell) const
// {
// int bestslvl = 0;
// if(VLC->spellh->spells[spell].air)
// if(getSecSkillLevel(15) >= bestslvl)
// {
// bestslvl = getSecSkillLevel(15);
// }
// if(VLC->spellh->spells[spell].fire)
// if(getSecSkillLevel(14) >= bestslvl)
// {
// bestslvl = getSecSkillLevel(14);
// }
// if(VLC->spellh->spells[spell].water)
// if(getSecSkillLevel(16) >= bestslvl)
// {
// bestslvl = getSecSkillLevel(16);
// }
// if(VLC->spellh->spells[spell].earth)
// if(getSecSkillLevel(17) >= bestslvl)
// {
// bestslvl = getSecSkillLevel(17);
// }
// return bestslvl;
// }
2008-11-11 17:17:58 +02: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
{
2009-03-12 20:06:02 +02:00
ID = HEROI_TYPE ;
2008-12-22 19:48:41 +02:00
tacticFormationEnabled = inTownGarrison = false ;
mana = movement = portrait = level = - 1 ;
isStanding = true ;
moveDir = 4 ;
exp = 0xffffffff ;
visitedTown = NULL ;
type = NULL ;
2009-07-19 04:00:19 +03:00
boat = NULL ;
2008-12-22 19:48:41 +02:00
secSkills . push_back ( std : : make_pair ( - 1 , - 1 ) ) ;
2010-07-15 22:38:15 +03:00
speciality . nodeType = CBonusSystemNode : : SPECIALITY ;
2008-12-22 19:48:41 +02:00
}
void CGHeroInstance : : initHero ( int SUBID )
{
subID = SUBID ;
initHero ( ) ;
}
void CGHeroInstance : : initHero ( )
{
2010-05-02 21:20:26 +03:00
assert ( validTypes ( true ) ) ;
2009-03-12 20:06:02 +02:00
if ( ID = = HEROI_TYPE )
2009-02-14 21:12:40 +02:00
initHeroDefInfo ( ) ;
2008-12-22 19:48:41 +02:00
if ( ! type )
type = VLC - > heroh - > heroes [ subID ] ;
2009-09-14 01:45:58 +03:00
if ( ! vstd : : contains ( spells , 0xffffffff ) & & type - > startingSpell > = 0 ) //hero starts with a spell
2009-07-03 21:40:36 +03:00
spells . insert ( type - > startingSpell ) ;
2009-09-14 01:45:58 +03:00
else //remove placeholder
spells - = 0xffffffff ;
if ( ! vstd : : contains ( artifWorn , 16 ) & & type - > startingSpell > = 0 ) //no catapult means we haven't read pre-existant set
{
2010-07-20 21:34:32 +03:00
VLC - > arth - > equipArtifact ( artifWorn , 17 , 0 ) ; //give spellbook
2008-12-22 19:48:41 +02:00
}
2010-07-20 21:34:32 +03:00
VLC - > arth - > equipArtifact ( artifWorn , 16 , 3 ) ; //everyone has a catapult
2008-12-22 19:48:41 +02:00
if ( portrait < 0 | | portrait = = 255 )
portrait = subID ;
2010-05-02 21:20:26 +03:00
if ( ! hasBonus ( Selector : : sourceType ( Bonus : : HERO_BASE_SKILL ) ) )
2008-12-22 19:48:41 +02:00
{
2010-05-02 21:20:26 +03:00
pushPrimSkill ( PrimarySkill : : ATTACK , type - > heroClass - > initialAttack ) ;
pushPrimSkill ( PrimarySkill : : DEFENSE , type - > heroClass - > initialDefence ) ;
pushPrimSkill ( PrimarySkill : : SPELL_POWER , type - > heroClass - > initialPower ) ;
pushPrimSkill ( PrimarySkill : : KNOWLEDGE , type - > heroClass - > initialKnowledge ) ;
2008-12-22 19:48:41 +02:00
}
if ( secSkills . size ( ) = = 1 & & secSkills [ 0 ] = = std : : pair < ui8 , ui8 > ( - 1 , - 1 ) ) //set secondary skills to default
secSkills = type - > secSkillsInit ;
if ( ! name . length ( ) )
name = type - > name ;
if ( exp = = 0xffffffff )
{
exp = 40 + ( ran ( ) ) % 50 ;
level = 1 ;
}
else
{
level = VLC - > heroh - > level ( exp ) ;
}
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
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
2009-11-21 18:37:27 +02:00
if ( mana < 0 )
mana = manaLimit ( ) ; //after all bonuses are taken into account
2008-12-22 19:48:41 +02:00
}
2010-07-08 08:52:11 +03:00
void CGHeroInstance : : initArmy ( CCreatureSet * dst /*= NULL*/ )
{
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 ;
2010-07-26 23:56:39 +03:00
for ( int stackNo = 0 ; stackNo < howManyStacks ; stackNo + + )
2010-07-08 08:52:11 +03:00
{
int creID = ( VLC - > creh - > nameToID [ type - > refTypeStack [ stackNo ] ] ) ;
int range = type - > highStack [ stackNo ] - type - > lowStack [ stackNo ] ;
int count = ran ( ) % ( range + 1 ) + type - > lowStack [ stackNo ] ;
if ( creID > = 145 & & creID < = 149 ) //war machine
{
warMachinesGiven + + ;
switch ( creID )
{
case 145 : //catapult
2010-07-20 21:34:32 +03:00
VLC - > arth - > equipArtifact ( artifWorn , 16 , 3 ) ;
2010-07-08 08:52:11 +03:00
break ;
default :
VLC - > arth - > equipArtifact (
artifWorn ,
9 + CArtHandler : : convertMachineID ( creID , true ) ,
2010-07-20 21:34:32 +03:00
CArtHandler : : convertMachineID ( creID , true ) ) ;
2010-07-08 08:52:11 +03:00
break ;
}
}
else
dst - > addStack ( stackNo - warMachinesGiven , CStackInstance ( creID , count ) ) ;
}
}
2009-02-01 16:11:41 +02:00
void CGHeroInstance : : initHeroDefInfo ( )
{
2009-03-12 20:06:02 +02:00
if ( ! defInfo | | defInfo - > id ! = HEROI_TYPE )
2009-02-01 16:11:41 +02:00
{
defInfo = new CGDefInfo ( ) ;
2009-03-12 20:06:02 +02:00
defInfo - > id = HEROI_TYPE ;
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 - > handler = NULL ;
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 ( )
{
}
bool CGHeroInstance : : needsLastStack ( ) const
{
return true ;
}
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
2009-03-12 20:06:02 +02:00
if ( ID = = HEROI_TYPE ) //hero
2008-12-22 19:48:41 +02:00
{
2010-08-03 15:34:06 +03:00
if ( cb - > getPlayerRelations ( tempOwner , h - > tempOwner ) ) //our or ally hero
2009-02-14 21:12:40 +02:00
{
//exchange
2009-06-16 14:18:14 +03:00
cb - > heroExchange ( id , h - > 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
}
2009-02-14 21:12:40 +02:00
else if ( ID = = 62 ) //prison
2008-12-22 19:48:41 +02:00
{
2009-04-24 00:09:10 +03:00
InfoWindow iw ;
iw . player = h - > tempOwner ;
iw . soundID = soundBase : : ROGUE ;
2009-02-14 21:12:40 +02:00
if ( cb - > getHeroCount ( h - > tempOwner , false ) < 8 ) //free hero slot
{
2009-02-20 12:36:15 +02:00
cb - > changeObjPos ( id , pos + int3 ( 1 , 0 , 0 ) , 0 ) ;
2010-05-02 21:20:26 +03:00
cb - > setObjProperty ( id , ObjProperty : : ID , HEROI_TYPE ) ; //set ID to 34
2009-02-14 21:12:40 +02:00
cb - > giveHero ( id , h - > tempOwner ) ; //recreates def and adds hero to player
iw . text < < std : : pair < ui8 , ui32 > ( 11 , 102 ) ;
}
else //already 8 wandering heroes
{
iw . text < < std : : pair < ui8 , ui32 > ( 11 , 103 ) ;
}
2009-04-24 00:09:10 +03:00
cb - > showInfoDialog ( & iw ) ;
2008-12-22 19:48:41 +02:00
}
}
const std : : string & CGHeroInstance : : getBiography ( ) const
{
if ( biography . length ( ) )
return biography ;
else
return VLC - > generaltexth - > hTxts [ subID ] . biography ;
}
void CGHeroInstance : : initObj ( )
{
2008-12-27 03:01:59 +02:00
blockVisit = true ;
2010-07-06 10:32:40 +03:00
speciality . growthsWithLevel = false ;
Bonus bonus ;
2010-07-07 05:29:07 +03:00
if ( ! type )
return ; //TODO support prison
2010-07-20 21:34:32 +03:00
for ( std : : vector < specialInfo > : : const_iterator it = type - > spec . begin ( ) ; it ! = type - > spec . end ( ) ; it + + )
2010-07-06 10:32:40 +03:00
{
bonus . val = it - > val ;
bonus . id = id ; //from the hero, speciality has no unique id
bonus . duration = Bonus : : PERMANENT ;
bonus . source = Bonus : : HERO_SPECIAL ;
switch ( it - > type )
{
case 1 : // creature speciality
{
2010-07-12 13:20:25 +03:00
speciality . growthsWithLevel = true ;
const CCreature & specCreature = * VLC - > creh - > creatures [ it - > additionalinfo ] ; //creature in which we have specialty
int creLevel = specCreature . level ;
2010-07-08 22:10:26 +03:00
if ( ! creLevel ) //TODO: set fixed level for War Machines
2010-07-07 05:29:07 +03:00
{
2010-07-08 22:10:26 +03:00
if ( it - > additionalinfo = = 146 )
2010-07-07 05:29:07 +03:00
creLevel = 5 ; //treat ballista as 5-level
else
{
2010-07-12 13:20:25 +03:00
tlog2 < < " Warning: unknown level of " < < specCreature . namePl < < std : : endl ;
2010-07-07 05:29:07 +03:00
continue ;
}
}
2010-07-13 22:55:13 +03:00
bonus . limiter = new CCreatureTypeLimiter ( specCreature , true ) ; //with upgrades
2010-07-12 13:20:25 +03:00
bonus . type = Bonus : : PRIMARY_SKILL ;
2010-07-13 22:55:13 +03:00
bonus . additionalInfo = it - > additionalinfo ;
2010-07-07 05:29:07 +03:00
bonus . valType = Bonus : : ADDITIVE_VALUE ;
2010-07-12 13:20:25 +03:00
bonus . subtype = PrimarySkill : : ATTACK ;
2010-07-06 10:32:40 +03:00
speciality . bonuses . push_back ( bonus ) ;
2010-07-12 13:20:25 +03:00
bonus . subtype = PrimarySkill : : DEFENSE ;
2010-07-06 10:32:40 +03:00
speciality . bonuses . push_back ( bonus ) ;
2010-07-13 22:55:13 +03:00
//values will be calculated later
2010-07-12 13:20:25 +03:00
2010-07-08 22:10:26 +03:00
bonus . type = Bonus : : STACKS_SPEED ;
bonus . val = 1 ; //+1 speed
2010-07-06 10:32:40 +03:00
speciality . bonuses . push_back ( bonus ) ;
}
break ;
case 2 : //secondary skill
speciality . growthsWithLevel = true ;
2010-07-07 15:51:28 +03:00
bonus . type = Bonus : : SPECIAL_SECONDARY_SKILL ; //needs to be recalculated with level, based on this value
2010-07-21 12:00:24 +03:00
bonus . valType = Bonus : : BASE_NUMBER ; // to receive nonzero value
2010-07-07 15:51:28 +03:00
bonus . subtype = it - > subtype ; //skill id
bonus . val = it - > val ; //value per level, in percent
2010-07-21 12:00:24 +03:00
speciality . bonuses . push_back ( bonus ) ;
2010-07-07 15:51:28 +03:00
switch ( it - > additionalinfo )
2010-07-06 10:32:40 +03:00
{
case 0 : //normal
bonus . valType = Bonus : : PERCENT_TO_BASE ;
break ;
case 1 : //when it's navigation or there's no 'base' at all
bonus . valType = Bonus : : PERCENT_TO_ALL ;
break ;
}
2010-07-21 12:00:24 +03:00
bonus . type = Bonus : : SECONDARY_SKILL_PREMY ; //value will be calculated later
2010-07-08 22:10:26 +03:00
speciality . bonuses . push_back ( bonus ) ;
2010-07-06 10:32:40 +03:00
break ;
2010-07-17 16:49:58 +03:00
case 3 : //spell damage bonus, level dependant but calculated elsehwere
2010-07-06 10:32:40 +03:00
bonus . type = Bonus : : SPECIAL_SPELL_LEV ;
bonus . subtype = it - > subtype ;
speciality . bonuses . push_back ( bonus ) ;
break ;
case 4 : //creature stat boost
2010-07-08 22:10:26 +03:00
switch ( it - > subtype )
{
case 1 : //attack
2010-07-15 22:38:15 +03:00
bonus . type = Bonus : : PRIMARY_SKILL ;
bonus . subtype = PrimarySkill : : ATTACK ;
break ;
2010-07-08 22:10:26 +03:00
case 2 : //defense
bonus . type = Bonus : : PRIMARY_SKILL ;
2010-07-15 22:38:15 +03:00
bonus . subtype = PrimarySkill : : DEFENSE ;
break ;
2010-07-17 16:11:12 +03:00
case 3 :
2010-07-15 22:38:15 +03:00
bonus . type = Bonus : : CREATURE_DAMAGE ;
bonus . subtype = 0 ; //both min and max
break ;
case 4 : //hp
bonus . type = Bonus : : STACK_HEALTH ;
2010-07-08 22:10:26 +03:00
break ;
case 5 :
bonus . type = Bonus : : STACKS_SPEED ;
break ;
default :
2010-07-15 22:38:15 +03:00
continue ;
2010-07-08 22:10:26 +03:00
}
2010-07-06 10:32:40 +03:00
bonus . valType = Bonus : : ADDITIVE_VALUE ;
2010-07-15 22:38:15 +03:00
bonus . limiter = new CCreatureTypeLimiter ( * VLC - > creh - > creatures [ it - > additionalinfo ] , true ) ;
2010-07-06 10:32:40 +03:00
speciality . bonuses . push_back ( bonus ) ;
break ;
case 5 : //spell damage bonus in percent
bonus . type = Bonus : : SPECIFIC_SPELL_DAMAGE ;
2010-07-17 16:11:12 +03:00
bonus . valType = Bonus : : BASE_NUMBER ; // current spell system is screwed
bonus . subtype = it - > subtype ; //spell id
2010-07-06 10:32:40 +03:00
speciality . bonuses . push_back ( bonus ) ;
break ;
case 6 : //damage bonus for bless (Adela)
bonus . type = Bonus : : SPECIAL_BLESS_DAMAGE ;
bonus . additionalInfo = it - > additionalinfo ; //damage factor
speciality . bonuses . push_back ( bonus ) ;
break ;
case 7 : //maxed mastery for spell
bonus . type = Bonus : : MAXED_SPELL ;
speciality . bonuses . push_back ( bonus ) ;
break ;
case 8 : //peculiar spells - enchantments
bonus . type = Bonus : : SPECIAL_PECULIAR_ENCHANT ;
bonus . subtype = it - > subtype ; //0, 1 for Coronius
speciality . bonuses . push_back ( 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
{
std : : vector < CCreature * > * creatures = & VLC - > creh - > creatures ;
2010-07-06 10:32:40 +03:00
bonus . type = Bonus : : SPECIAL_UPGRADE ;
2010-07-17 09:49:16 +03:00
bonus . subtype = it - > subtype ; //base id
bonus . additionalInfo = it - > additionalinfo ; //target id
2010-07-06 10:32:40 +03:00
speciality . bonuses . push_back ( bonus ) ;
2010-07-17 09:49:16 +03:00
for ( std : : set < ui32 > : : iterator i = ( * creatures ) [ it - > subtype ] - > upgrades . begin ( ) ;
i ! = ( * creatures ) [ it - > subtype ] - > upgrades . end ( ) ; i + + )
2010-07-06 10:32:40 +03:00
{
2010-07-17 09:49:16 +03:00
bonus . subtype = * i ; //propagate for regular upgrades of base creature
speciality . bonuses . push_back ( 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
bonus . type = Bonus : : GENERATE_RESOURCE ;
bonus . subtype = it - > subtype ;
speciality . bonuses . push_back ( bonus ) ;
break ;
case 11 : //starting skill with mastery (Adrienne)
cb - > changeSecSkill ( id , it - > val , it - > additionalinfo ) ; //simply give it and forget
break ;
case 12 : //army speed
bonus . type = Bonus : : STACKS_SPEED ;
speciality . bonuses . push_back ( bonus ) ;
break ;
case 13 : //Dragon bonuses (Mutare)
2010-07-08 22:10:26 +03:00
bonus . type = Bonus : : PRIMARY_SKILL ;
2010-07-06 10:32:40 +03:00
bonus . valType = Bonus : : ADDITIVE_VALUE ;
2010-07-16 09:18:41 +03:00
switch ( it - > subtype )
{
case 1 :
bonus . subtype = PrimarySkill : : ATTACK ;
break ;
case 2 :
bonus . subtype = PrimarySkill : : DEFENSE ;
break ;
}
2010-07-06 10:32:40 +03:00
for ( std : : vector < CCreature * > : : iterator i = VLC - > creh - > creatures . begin ( ) ; i ! = VLC - > creh - > creatures . end ( ) ; i + + )
{ //TODO: what if creature changes type during the game (Dragon Eye Ring?)
if ( ( * i ) - > hasBonusOfType ( Bonus : : DRAGON_NATURE ) ) //TODO: implement it!
{
2010-07-16 09:18:41 +03:00
bonus . limiter = new CCreatureTypeLimiter ( * * i , false ) ;
2010-07-06 10:32:40 +03:00
speciality . bonuses . push_back ( bonus ) ;
}
}
2010-07-06 13:02:38 +03:00
break ;
2010-07-06 10:32:40 +03:00
default :
tlog2 < < " Unexpected hero speciality " < < type < < ' \n ' ;
}
}
2010-07-17 20:02:11 +03:00
//initialize bonuses
for ( std : : vector < std : : pair < ui8 , ui8 > > : : iterator it = secSkills . begin ( ) ; it ! = secSkills . end ( ) ; it + + )
2010-07-19 21:30:51 +03:00
updateSkill ( it - > first , it - > second ) ;
2010-07-13 22:55:13 +03:00
UpdateSpeciality ( ) ;
}
void CGHeroInstance : : UpdateSpeciality ( )
{
if ( speciality . growthsWithLevel )
{
std : : vector < CCreature * > * creatures = & VLC - > creh - > creatures ;
for ( std : : list < Bonus > : : iterator it = speciality . bonuses . begin ( ) ; it ! = speciality . bonuses . end ( ) ; it + + )
{
switch ( it - > type )
{
case Bonus : : SECONDARY_SKILL_PREMY :
2010-07-21 12:00:24 +03:00
it - > val = ( speciality . valOfBonuses ( Bonus : : SPECIAL_SECONDARY_SKILL , it - > subtype ) * level ) ;
break ; //use only hero skills as bonuses to avoid feedback loop
2010-07-13 22:55:13 +03:00
case Bonus : : PRIMARY_SKILL : //for crearures, that is
int creLevel = ( * creatures ) [ it - > additionalInfo ] - > level ;
if ( ! creLevel )
{
if ( it - > additionalInfo = = 146 )
creLevel = 5 ; //treat ballista as 5-level
else
{
tlog2 < < " Warning: unknown level of " < < ( * creatures ) [ it - > additionalInfo ] - > namePl < < std : : endl ;
continue ;
}
}
double primSkillModifier = ( int ) ( level / creLevel ) / 20.0 ;
2010-07-15 23:09:21 +03:00
int param ;
2010-07-13 22:55:13 +03:00
switch ( it - > subtype )
{
case PrimarySkill : : ATTACK :
2010-07-15 23:09:21 +03:00
param = ( * creatures ) [ it - > additionalInfo ] - > attack ;
break ;
2010-07-13 22:55:13 +03:00
case PrimarySkill : : DEFENSE :
2010-07-15 23:09:21 +03:00
param = ( * creatures ) [ it - > additionalInfo ] - > defence ;
2010-07-13 22:55:13 +03:00
break ;
}
2010-07-15 23:09:21 +03:00
it - > val = ceil ( param * ( 1 + primSkillModifier ) ) - param ; //yep, overcomplicated but matches original
2010-07-13 22:55:13 +03:00
break ;
}
}
}
2008-12-22 19:48:41 +02:00
}
2010-07-19 21:30:51 +03:00
void CGHeroInstance : : updateSkill ( int which , int val )
2010-07-17 20:02:11 +03:00
{
int skillVal = 0 ;
switch ( which )
{
case 1 : //Archery
switch ( val )
{
case 1 :
skillVal = 10 ; break ;
case 2 :
skillVal = 25 ; break ;
case 3 :
skillVal = 50 ; break ;
}
break ;
case 2 : //Logistics
skillVal = 10 * val ; break ;
case 5 : //Navigation
skillVal = 50 * val ; break ;
case 8 : //Mysticism
skillVal = val ; break ;
case 11 : //eagle Eye
skillVal = 30 + 10 * val ; break ;
case 12 : //Necromancy
skillVal = 10 * val ; break ;
case 22 : //Offense
skillVal = 10 * val ; break ;
case 23 : //Armorer
skillVal = 5 * val ; break ;
case 24 : //Intelligence
skillVal = 25 < < val - 1 ; break ;
case 25 : //Sorcery
skillVal = 5 * val ; break ;
case 26 : //Resistance
skillVal = 5 < < val - 1 ; break ;
case 27 : //First Aid
skillVal = 25 + 25 * val ; break ;
}
2010-07-19 21:30:51 +03:00
if ( skillVal ) //we don't need bonuses of other types here
2010-07-17 20:02:11 +03:00
{
2010-07-21 22:50:15 +03:00
Bonus * b = bonuses . getFirst ( Selector : : typeSybtype ( Bonus : : SECONDARY_SKILL_PREMY , which ) & & Selector : : sourceType ( Bonus : : SECONDARY_SKILL ) ) ;
2010-07-21 12:00:24 +03:00
if ( b ) //only local hero bonus
2010-07-19 21:30:51 +03:00
{
2010-07-21 12:00:24 +03:00
b - > val = skillVal ;
2010-07-19 21:30:51 +03:00
}
else
{
2010-07-21 12:00:24 +03:00
Bonus bonus ( Bonus : : PERMANENT , Bonus : : SECONDARY_SKILL_PREMY , id , skillVal , ID , which , Bonus : : BASE_NUMBER ) ;
bonus . source = Bonus : : SECONDARY_SKILL ;
bonuses . push_back ( bonus ) ;
2010-07-19 21:30:51 +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 )
setStackCount ( 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
{
return sqrt ( ( 1.0 + 0.05 * getPrimSkillLevel ( 0 ) ) * ( 1.0 + 0.05 * getPrimSkillLevel ( 1 ) ) ) ;
}
int CGHeroInstance : : getTotalStrength ( ) const
{
2009-04-16 03:28:54 +03:00
double ret = getHeroStrength ( ) * getArmyStrength ( ) ;
return ( int ) ret ;
2009-04-12 04:48:50 +03: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
{ \
int thisSchool = std : : max < int > ( getSecSkillLevel ( 14 + ( schoolMechanicsId ) ) , valOfBonuses ( Bonus : : MAGIC_SCHOOL_SKILL , 1 < < ( schoolMechanicsId ) ) ) ; \
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
2010-07-21 13:09:29 +03:00
amax ( skill , valOfBonuses ( Bonus : : MAGIC_SCHOOL_SKILL , 0 ) ) ; //any school bonus
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
{
if ( ! getArt ( 17 ) ) //if hero has no spellbook
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-04-02 05:07:40 +03:00
CStackInstance CGHeroInstance : : calculateNecromancy ( const BattleResult & battleResult ) const
2009-09-01 01:04:00 +03:00
{
const ui8 necromancyLevel = getSecSkillLevel ( 12 ) ;
// Hero knows necromancy.
2010-05-14 05:18:37 +03:00
if ( necromancyLevel > 0 )
{
2010-07-17 20:02:11 +03:00
double necromancySkill = valOfBonuses ( Bonus : : SECONDARY_SKILL_PREMY , 12 ) / 100.0 ;
2010-05-14 05:18:37 +03:00
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.
const ui32 creatureTypes [ ] = { 56 , 58 , 60 , 64 } ; // IDs for Skeletons, Walking Dead, Wights and Liches respectively.
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
for ( std : : map < ui32 , si32 > : : const_iterator it = casualties . begin ( ) ; it ! = casualties . end ( ) ; it + + )
{
// Get lost enemy hit points convertible to units.
const ui32 raisedHP = VLC - > creh - > creatures [ it - > first ] - > valOfBonuses ( Bonus : : STACK_HEALTH ) * it - > second * necromancySkill ;
raisedUnits + = std : : min < ui32 > ( raisedHP / raisedUnitHP , it - > second * necromancySkill ) ; //limit to % of HP and % of original stack count
}
2009-09-01 01:04:00 +03:00
// Make room for new units.
2010-05-02 21:20:26 +03:00
int slot = getSlotFor ( raisedUnitType - > idNumber ) ;
2009-09-24 16:23:52 +03:00
if ( slot = = - 1 )
{
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-04-02 05:07:40 +03:00
return CStackInstance ( raisedUnitType - > idNumber , raisedUnits ) ;
2009-09-01 01:04:00 +03:00
}
2010-04-02 05:07:40 +03:00
return CStackInstance ( ) ;
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-04-02 05:07:40 +03:00
void CGHeroInstance : : showNecromancyDialog ( const CStackInstance & raisedStack ) const
2009-09-01 01:04:00 +03:00
{
InfoWindow iw ;
iw . soundID = soundBase : : GENIE ;
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)
{
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 ) ;
iw . text . addReplacement ( MetaString : : CRE_PL_NAMES , raisedStack . type - > idNumber ) ;
}
else // Practicing the dark arts of necromancy, ... (singular)
{
2009-09-01 01:04:00 +03:00
iw . text . addTxt ( MetaString : : GENERAL_TXT , 146 ) ;
2010-04-02 05:07:40 +03:00
iw . text . addReplacement ( MetaString : : CRE_SING_NAMES , raisedStack . type - > idNumber ) ;
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
{
2010-05-02 21:20:26 +03:00
return 5 + getSecSkillLevel ( 3 ) + 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
2010-07-17 20:02:11 +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
}
2009-05-22 02:50:45 +03:00
si32 CGHeroInstance : : getArtPos ( int aid ) const
{
for ( std : : map < ui16 , ui32 > : : const_iterator i = artifWorn . begin ( ) ; i ! = artifWorn . end ( ) ; i + + )
if ( i - > second = = aid )
return i - > first ;
return - 1 ;
}
2009-12-30 17:33:28 +02: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 )
{
2010-06-26 19:02:10 +03:00
const CArtifact & artifact = * VLC - > arth - > artifacts [ aid ] ;
2009-12-30 17:33:28 +02:00
2010-06-26 19:02:10 +03:00
if ( artifact . isBig ( ) )
{
for ( std : : vector < ui16 > : : const_iterator it = artifact . possibleSlots . begin ( ) ; it ! = artifact . possibleSlots . end ( ) ; + + it )
{
if ( ! vstd : : contains ( artifWorn , * it ) )
{
2010-07-20 21:34:32 +03:00
VLC - > arth - > equipArtifact ( artifWorn , * it , aid ) ;
2009-12-30 17:33:28 +02:00
break ;
}
}
2010-06-26 19:02:10 +03:00
}
else
{
2009-12-30 17:33:28 +02:00
artifacts . push_back ( aid ) ;
}
}
2010-01-29 22:52:45 +02:00
bool CGHeroInstance : : hasArt ( ui32 aid ) const
{
if ( vstd : : contains ( artifacts , aid ) )
return true ;
for ( std : : map < ui16 , ui32 > : : const_iterator i = artifWorn . begin ( ) ; i ! = artifWorn . end ( ) ; i + + )
if ( i - > second = = aid )
return true ;
2010-01-30 14:46:15 +02:00
return false ;
2010-01-29 22:52:45 +02:00
}
2010-03-11 01:16:30 +02:00
int CGHeroInstance : : getBoatType ( ) const
{
int alignment = type - > heroType / 6 ;
switch ( alignment )
{
case 0 :
return 1 ; //good
case 1 :
return 0 ; //evil
case 2 :
return 2 ;
default :
2010-03-21 00:17:19 +02:00
throw std : : string ( " 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 ) } ;
for ( size_t i = 0 ; i < ARRAY_COUNT ( dirs ) ; i + + )
offsets + = dirs [ i ] ;
}
int CGHeroInstance : : getSpellCost ( const CSpell * sp ) const
{
return sp - > costs [ getSpellSchoolLevel ( sp ) ] ;
}
2010-05-02 21:20:26 +03:00
void CGHeroInstance : : getParents ( TCNodes & out , const CBonusSystemNode * root /*= NULL*/ ) const
2010-03-21 00:17:19 +02:00
{
2010-05-02 21:20:26 +03:00
CArmedInstance : : getParents ( out , root ) ; // if(visitedTown && source != this && source != visitedTown)
// out.insert(visitedTown);
if ( ( root = = this | | contains ( static_cast < const CStackInstance * > ( root ) ) ) & & visitedTown )
out . insert ( visitedTown ) ;
2010-07-06 10:32:40 +03:00
2010-07-20 21:34:32 +03:00
for ( std : : map < ui16 , ui32 > : : const_iterator i = artifWorn . begin ( ) ; i ! = artifWorn . end ( ) ; i + + )
out . insert ( VLC - > arth - > artifacts [ i - > second ] ) ;
out . insert ( & speciality ) ;
2010-05-02 21:20:26 +03:00
}
void CGHeroInstance : : pushPrimSkill ( int which , int val )
{
bonuses . push_back ( Bonus ( Bonus : : PERMANENT , Bonus : : PRIMARY_SKILL , Bonus : : HERO_BASE_SKILL , val , id , which ) ) ;
}
void CGHeroInstance : : getBonuses ( BonusList & out , const CSelector & selector , const CBonusSystemNode * root /*= NULL*/ ) const
{
2010-05-26 12:47:53 +03:00
# define FOREACH_OWNER_TOWN(town) if(const PlayerState *p = cb->getPlayerState(tempOwner)) BOOST_FOREACH(const CGTownInstance *town, p->towns)
2010-05-02 21:20:26 +03:00
CArmedInstance : : getBonuses ( out , selector , root ) ;
//TODO eliminate by moving secondary skills effects to bonus system
if ( Selector : : matchesType ( selector , Bonus : : LUCK ) )
2010-04-03 06:33:46 +03:00
{
2010-05-02 21:20:26 +03:00
//luck skill
if ( int luckSkill = getSecSkillLevel ( 9 ) )
out . push_back ( Bonus ( Bonus : : PERMANENT , Bonus : : LUCK , Bonus : : SECONDARY_SKILL , luckSkill , 9 , VLC - > generaltexth - > arraytxt [ 73 + luckSkill ] ) ) ;
2010-05-14 05:18:37 +03:00
//guardian spirit
2010-05-26 12:47:53 +03:00
FOREACH_OWNER_TOWN ( t )
2010-05-14 05:18:37 +03:00
if ( t - > subID = = 1 & & vstd : : contains ( t - > builtBuildings , 26 ) ) //rampart with grail
out . push_back ( Bonus ( Bonus : : PERMANENT , Bonus : : LUCK , Bonus : : TOWN_STRUCTURE , + 2 , 26 , VLC - > generaltexth - > buildings [ 1 ] [ 26 ] . first + " +2 " ) ) ;
}
if ( Selector : : matchesType ( selector , Bonus : : SEA_MOVEMENT ) )
{
//lighthouses
2010-05-26 12:47:53 +03:00
FOREACH_OWNER_TOWN ( t )
2010-05-14 05:18:37 +03:00
if ( t - > subID = = 0 & & vstd : : contains ( t - > builtBuildings , 17 ) ) //castle
out . push_back ( Bonus ( Bonus : : PERMANENT , Bonus : : SEA_MOVEMENT , Bonus : : TOWN_STRUCTURE , + 500 , 17 , VLC - > generaltexth - > buildings [ 0 ] [ 17 ] . first + " +500 " ) ) ;
2010-04-03 06:33:46 +03:00
}
2010-03-21 00:17:19 +02:00
2010-05-02 21:20:26 +03:00
if ( Selector : : matchesType ( selector , Bonus : : MORALE ) )
{
//leadership
if ( int moraleSkill = getSecSkillLevel ( 6 ) )
out . push_back ( Bonus ( Bonus : : PERMANENT , Bonus : : MORALE , Bonus : : SECONDARY_SKILL , moraleSkill , 6 , VLC - > generaltexth - > arraytxt [ 104 + moraleSkill ] ) ) ;
2010-05-14 05:18:37 +03:00
//colossus
2010-05-26 12:47:53 +03:00
FOREACH_OWNER_TOWN ( t )
2010-05-14 05:18:37 +03:00
if ( t - > subID = = 0 & & vstd : : contains ( t - > builtBuildings , 26 ) ) //castle
out . push_back ( Bonus ( Bonus : : PERMANENT , Bonus : : MORALE , Bonus : : TOWN_STRUCTURE , + 2 , 26 , VLC - > generaltexth - > buildings [ 0 ] [ 26 ] . first + " +2 " ) ) ;
}
if ( Selector : : matchesTypeSubtype ( selector , Bonus : : SECONDARY_SKILL_PREMY , 12 ) ) //necromancy
{
2010-05-26 12:47:53 +03:00
FOREACH_OWNER_TOWN ( t )
2010-05-14 05:18:37 +03:00
{
if ( t - > subID = = 4 ) //necropolis
{
if ( vstd : : contains ( t - > builtBuildings , 21 ) ) //necromancy amplifier
out . push_back ( Bonus ( Bonus : : PERMANENT , Bonus : : SECONDARY_SKILL_PREMY , Bonus : : TOWN_STRUCTURE , + 10 , 21 , VLC - > generaltexth - > buildings [ 4 ] [ 21 ] . first + " +10% " , 12 ) ) ;
if ( vstd : : contains ( t - > builtBuildings , 26 ) ) //grail - Soul prison
out . push_back ( Bonus ( Bonus : : PERMANENT , Bonus : : SECONDARY_SKILL_PREMY , Bonus : : TOWN_STRUCTURE , + 20 , 26 , VLC - > generaltexth - > buildings [ 4 ] [ 26 ] . first + " +20% " , 12 ) ) ;
}
}
2010-05-02 21:20:26 +03:00
}
2010-03-21 00:17:19 +02:00
}
2010-07-20 09:05:45 +03:00
EAlignment CGHeroInstance : : getAlignment ( ) const
{
return type - > heroClass - > getAlignment ( ) ;
}
2009-07-06 22:41:27 +03:00
void CGDwelling : : initObj ( )
{
switch ( ID )
{
case 17 :
2009-07-09 22:15:22 +03:00
{
int 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 ) ;
hoverName = VLC - > generaltexth - > creGens [ subID ] ;
if ( crs - > level > 4 )
2010-06-28 20:49:15 +03:00
addStack ( 0 , CStackInstance ( crs , ( crs - > growth ) * 3 ) ) ;
2009-10-26 11:11:10 +02:00
if ( getOwner ( ) ! = 255 )
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
2009-07-06 22:41:27 +03:00
case 20 :
creatures . resize ( 4 ) ;
2009-07-26 13:43:22 +03:00
if ( subID = = 1 ) //Golem Factory
2009-07-06 22:41:27 +03:00
{
creatures [ 0 ] . second . push_back ( 32 ) ; //Stone Golem
creatures [ 1 ] . second . push_back ( 33 ) ; //Iron Golem
creatures [ 2 ] . second . push_back ( 116 ) ; //Gold Golem
creatures [ 3 ] . second . push_back ( 117 ) ; //Diamond Golem
2009-07-26 13:43:22 +03:00
//guards
2010-05-02 21:20:26 +03:00
addStack ( 0 , CStackInstance ( 116 , 9 ) ) ;
addStack ( 1 , CStackInstance ( 117 , 6 ) ) ;
2009-07-06 22:41:27 +03:00
}
2009-07-26 13:43:22 +03:00
else if ( subID = = 0 ) // Elemental Conflux
2009-07-06 22:41:27 +03:00
{
creatures [ 0 ] . second . push_back ( 112 ) ; //Air Elemental
2009-08-07 01:36:51 +03:00
creatures [ 1 ] . second . push_back ( 114 ) ; //Fire Elemental
creatures [ 2 ] . second . push_back ( 113 ) ; //Earth Elemental
2009-07-06 22:41:27 +03:00
creatures [ 3 ] . second . push_back ( 115 ) ; //Water Elemental
2009-07-26 13:43:22 +03:00
//guards
2010-05-02 21:20:26 +03:00
addStack ( 0 , CStackInstance ( 113 , 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
2010-07-24 00:05:49 +03:00
case 78 : //Refugee Camp
//is handled within newturn func
break ;
2010-05-15 11:33:32 +03:00
case 106 : //War Machine Factory
creatures . resize ( 3 ) ;
creatures [ 0 ] . second . push_back ( 146 ) ; //Ballista
creatures [ 1 ] . second . push_back ( 147 ) ; //First Aid Tent
creatures [ 2 ] . second . push_back ( 148 ) ; //Ammo Cart
break ;
2009-07-06 22:41:27 +03:00
default :
assert ( 0 ) ;
break ;
}
}
2009-10-26 11:11:10 +02:00
void CGDwelling : : setProperty ( ui8 what , ui32 val )
{
switch ( what )
{
2010-05-02 21:20:26 +03:00
case ObjProperty : : OWNER : //change owner
2009-10-26 11:11:10 +02:00
if ( ID = = 17 ) //single generators
{
if ( tempOwner ! = NEUTRAL_PLAYER )
{
std : : vector < CGDwelling * > * dwellings = & cb - > gameState ( ) - > players [ tempOwner ] . dwellings ;
dwellings - > erase ( std : : find ( dwellings - > begin ( ) , dwellings - > end ( ) , this ) ) ;
}
if ( val ! = NEUTRAL_PLAYER ) //can new owner be neutral?
cb - > gameState ( ) - > players [ val ] . dwellings . push_back ( this ) ;
}
break ;
2010-07-24 00:05:49 +03:00
case ObjProperty : : AVAILABLE_CREATURE :
creatures . resize ( 1 ) ;
creatures [ 0 ] . second . resize ( 1 ) ;
creatures [ 0 ] . second [ 0 ] = val ;
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
{
2010-07-24 00:05:49 +03:00
if ( ID = = 78 & & ! creatures [ 0 ] . first ) //Refugee Camp, no available cres
{
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 ;
}
2010-05-02 21:20:26 +03:00
if ( h - > tempOwner ! = tempOwner & & stacksCount ( ) > 0 ) //object is guarded
2009-07-09 22:15:22 +03:00
{
BlockingDialog bd ;
bd . player = h - > tempOwner ;
bd . flags = BlockingDialog : : ALLOW_CANCEL ;
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?
2009-07-26 13:43:22 +03:00
bd . text . addReplacement ( ID = = 17 ? MetaString : : CREGENS : MetaString : : CREGENS4 , subID ) ;
2010-05-02 21:20:26 +03:00
bd . text . addReplacement ( MetaString : : ARRAY_TXT , 176 + Slots ( ) . begin ( ) - > second . getQuantityID ( ) * 3 ) ;
bd . text . addReplacement ( Slots ( ) . begin ( ) - > second ) ;
2009-07-09 22:15:22 +03:00
cb - > showBlockingDialog ( & bd , boost : : bind ( & CGDwelling : : wantsFight , this , h , _1 ) ) ;
return ;
}
2010-05-15 11:33:32 +03:00
if ( h - > tempOwner ! = tempOwner & & ID ! = 106 )
2009-10-24 22:21:32 +03:00
{
2009-07-06 22:41:27 +03:00
cb - > setOwner ( id , h - > tempOwner ) ;
2009-10-24 22:21:32 +03:00
}
2009-07-06 22:41:27 +03:00
2009-07-09 22:15:22 +03:00
BlockingDialog bd ;
bd . player = h - > tempOwner ;
bd . flags = BlockingDialog : : ALLOW_CANCEL ;
2010-05-15 11:33:32 +03:00
if ( ID = = 17 | | ID = = 20 )
{
bd . text . addTxt ( MetaString : : ADVOB_TXT , ID = = 17 ? 35 : 36 ) ; //{%s} Would you like to recruit %s? / {%s} Would you like to recruit %s, %s, %s, or %s?
bd . text . addReplacement ( ID = = 17 ? MetaString : : CREGENS : MetaString : : CREGENS4 , subID ) ;
for ( size_t i = 0 ; i < creatures . size ( ) ; i + + )
bd . text . addReplacement ( MetaString : : CRE_PL_NAMES , creatures [ i ] . second [ 0 ] ) ;
}
2010-07-24 00:05:49 +03:00
else if ( ID = = 78 )
{
bd . text . addTxt ( MetaString : : ADVOB_TXT , 35 ) ; //{%s} Would you like to recruit %s?
bd . text . addReplacement ( MetaString : : OBJ_NAMES , ID ) ;
for ( size_t i = 0 ; i < creatures . size ( ) ; i + + )
bd . text . addReplacement ( MetaString : : CRE_PL_NAMES , creatures [ i ] . second [ 0 ] ) ;
}
2010-05-15 11:33:32 +03:00
else if ( ID = = 106 )
bd . text . addTxt ( MetaString : : ADVOB_TXT , 157 ) ; //{War Machine Factory} Would you like to purchase War Machines?
else
throw std : : string ( " Illegal dwelling! " ) ;
2009-08-07 01:36:51 +03:00
2009-07-09 22:15:22 +03:00
cb - > showBlockingDialog ( & bd , boost : : bind ( & CGDwelling : : heroAcceptsCreatures , this , h , _1 ) ) ;
2009-07-06 22:41:27 +03:00
}
void CGDwelling : : newTurn ( ) const
{
if ( cb - > getDate ( 1 ) ! = 1 ) //not first day of week
return ;
2010-05-15 11:33:32 +03:00
//town growths and War Machines Factories are handled separately
if ( ID = = TOWNI_TYPE | | ID = = 106 )
2009-07-31 23:10:22 +03:00
return ;
2009-07-06 22:41:27 +03:00
2010-07-24 00:05:49 +03:00
if ( ID = = 78 ) //if it's a refugee camp, we need to pick an available creature
{
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 ( ) )
{
2009-08-07 01:36:51 +03:00
if ( false /*accumulate creatures*/ )
2010-05-02 21:20:26 +03:00
sac . creatures [ i ] . first + = VLC - > creh - > creatures [ creatures [ i ] . second [ 0 ] ] - > growth ;
2009-08-07 01:36:51 +03:00
else
2010-05-02 21:20:26 +03:00
sac . creatures [ i ] . first = VLC - > creh - > creatures [ creatures [ i ] . second [ 0 ] ] - > growth ;
2009-07-06 22:41:27 +03:00
change = true ;
}
}
if ( change )
cb - > sendAndApply ( & sac ) ;
}
2009-07-09 22:15:22 +03:00
void CGDwelling : : heroAcceptsCreatures ( const CGHeroInstance * h , ui32 answer ) const
{
if ( ! answer )
return ;
int crid = creatures [ 0 ] . second [ 0 ] ;
2010-05-02 21:20:26 +03:00
CCreature * crs = VLC - > creh - > creatures [ crid ] ;
2009-07-09 22:15:22 +03:00
2010-07-24 00:05:49 +03:00
if ( crs - > level = = 1 & & ID ! = 78 ) //first level - creatures are for free
2009-07-09 22:15:22 +03:00
{
if ( creatures [ 0 ] . first ) //there are available creatures
{
2010-05-02 21:20:26 +03:00
int slot = h - > getSlotFor ( crid ) ;
2009-07-09 22:15:22 +03:00
if ( slot < 0 ) //no available slot
{
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 ;
SetGarrisons sg ;
2010-05-02 21:20:26 +03:00
sg . garrs [ h - > id ] = * h ;
sg . garrs [ h - > id ] . addToSlot ( slot , crid , creatures [ 0 ] . first ) ;
2009-07-09 22:15:22 +03:00
InfoWindow iw ;
iw . player = h - > tempOwner ;
iw . text . addTxt ( MetaString : : GENERAL_TXT , 423 ) ; //%d %s join your army.
iw . text . addReplacement ( creatures [ 0 ] . first ) ;
iw . text . addReplacement ( MetaString : : CRE_PL_NAMES , crid ) ;
cb - > showInfoDialog ( & iw ) ;
cb - > sendAndApply ( & sac ) ;
cb - > sendAndApply ( & sg ) ;
}
}
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
{
2010-05-15 11:33:32 +03:00
if ( ID = = 106 ) //pick available War Machines
{
//there is 1 war machine available to recruit if hero doesn't have one
SetAvailableCreatures sac ;
sac . tid = id ;
sac . creatures = creatures ;
sac . creatures [ 0 ] . first = ! h - > getArt ( 13 ) ; //ballista
sac . creatures [ 1 ] . first = ! h - > getArt ( 15 ) ; //first aid tent
sac . creatures [ 2 ] . first = ! h - > getArt ( 14 ) ; //ammo cart
cb - > sendAndApply ( & sac ) ;
}
2009-07-09 22:15:22 +03:00
OpenWindow ow ;
ow . id1 = id ;
2009-07-26 13:43:22 +03:00
ow . id2 = h - > id ;
2010-07-24 00:05:49 +03:00
ow . window = ( ID = = 17 | | ID = = 78 )
2009-07-26 13:43:22 +03:00
? OpenWindow : : RECRUITMENT_FIRST
: OpenWindow : : RECRUITMENT_ALL ;
2009-07-09 22:15:22 +03:00
cb - > sendAndApply ( & ow ) ;
}
}
void CGDwelling : : wantsFight ( const CGHeroInstance * h , ui32 answer ) const
{
if ( answer )
2009-09-13 01:17:23 +03:00
cb - > startBattleI ( h , this , boost : : bind ( & CGDwelling : : fightOver , this , h , _1 ) ) ;
2009-07-09 22:15:22 +03:00
}
void CGDwelling : : fightOver ( const CGHeroInstance * h , BattleResult * result ) const
{
if ( result - > winner = = 0 )
{
onHeroVisit ( h ) ;
}
}
2009-03-12 01:25:59 +02:00
int CGTownInstance : : getSightRadious ( ) const //returns sight distance
2007-10-27 22:38:48 +03:00
{
2009-08-23 18:02:21 +03:00
if ( subID = = 2 ) //tower
2009-08-24 13:23:44 +03:00
{
2010-02-13 06:47:31 +02:00
if ( ( builtBuildings . find ( 26 ) ) ! = builtBuildings . end ( ) ) //skyship
2009-11-11 19:45:03 +02:00
return - 1 ; //entire map
2009-08-23 18:02:21 +03:00
else if ( ( builtBuildings . find ( 21 ) ) ! = builtBuildings . end ( ) ) //lookout tower
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 )
{
case 11 : //add visitor of town building
2010-05-02 21:20:26 +03:00
bonusingBuildings [ val ] - > setProperty ( ObjProperty : : VISITORS , visitingHero - > id ) ;
2009-09-21 12:00:33 +03:00
break ;
2009-10-06 10:55:39 +03:00
case 12 :
bonusingBuildings [ val ] - > setProperty ( 12 , 0 ) ;
break ;
2009-12-30 22:49:10 +02:00
case 13 : //add garrisoned hero to visitors
2010-05-02 21:20:26 +03:00
bonusingBuildings [ val ] - > setProperty ( ObjProperty : : VISITORS , garrisonHero - > id ) ;
2009-12-30 22:49:10 +02:00
break ;
2010-01-28 18:15:46 +02:00
case 14 :
bonusValue . first = val ;
break ;
case 15 :
bonusValue . second = val ;
break ;
2009-09-21 12:00:33 +03:00
}
}
2008-02-18 23:14:28 +02:00
int CGTownInstance : : fortLevel ( ) const //0 - none, 1 - fort, 2 - citadel, 3 - castle
{
if ( ( builtBuildings . find ( 9 ) ) ! = builtBuildings . end ( ) )
return 3 ;
if ( ( builtBuildings . find ( 8 ) ) ! = builtBuildings . end ( ) )
return 2 ;
if ( ( builtBuildings . find ( 7 ) ) ! = builtBuildings . end ( ) )
return 1 ;
return 0 ;
}
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
{
if ( ( builtBuildings . find ( 13 ) ) ! = builtBuildings . end ( ) )
return 3 ;
if ( ( builtBuildings . find ( 12 ) ) ! = builtBuildings . end ( ) )
return 2 ;
if ( ( builtBuildings . find ( 11 ) ) ! = builtBuildings . end ( ) )
return 1 ;
if ( ( builtBuildings . find ( 10 ) ) ! = builtBuildings . end ( ) )
return 0 ;
return - 1 ;
}
2008-08-20 09:57:53 +03:00
int CGTownInstance : : mageGuildLevel ( ) const
{
if ( ( builtBuildings . find ( 4 ) ) ! = builtBuildings . end ( ) )
return 5 ;
if ( ( builtBuildings . find ( 3 ) ) ! = builtBuildings . end ( ) )
return 4 ;
if ( ( builtBuildings . find ( 2 ) ) ! = builtBuildings . end ( ) )
return 3 ;
if ( ( builtBuildings . find ( 1 ) ) ! = builtBuildings . end ( ) )
return 2 ;
if ( ( builtBuildings . find ( 0 ) ) ! = builtBuildings . end ( ) )
return 1 ;
return 0 ;
}
2008-06-03 16:15:34 +03:00
bool CGTownInstance : : creatureDwelling ( const int & level , bool upgraded ) const
2008-04-04 20:30:53 +03:00
{
2010-07-26 01:47:59 +03:00
if ( level < 0 | | level > = CREATURES_PER_TOWN )
return false ;
return vstd : : contains ( builtBuildings , 30 + level + upgraded * CREATURES_PER_TOWN ) ;
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
{
2010-07-10 19:50:23 +03:00
if ( level < 0 | | level > = CREATURES_PER_TOWN )
return 0 ;
2010-05-02 21:20:26 +03:00
int ret = VLC - > creh - > creatures [ town - > basicCreatures [ level ] ] - > growth ;
2008-04-14 20:45:01 +03:00
switch ( fortLevel ( ) )
{
case 3 :
ret * = 2 ; break ;
case 2 :
ret * = ( 1.5 ) ; break ;
}
2010-06-21 07:43:10 +03:00
if ( tempOwner ! = NEUTRAL_PLAYER )
{
ret * = ( 1 + cb - > gameState ( ) - > players [ tempOwner ] . valOfBonuses ( Bonus : : CREATURE_GROWTH_PERCENT ) / 100 ) ; //Statue of Legion
2010-06-29 12:59:14 +03:00
for ( std : : vector < CGDwelling * > : : const_iterator it = cb - > gameState ( ) - > players [ tempOwner ] . dwellings . begin ( ) ; it ! = cb - > gameState ( ) - > players [ tempOwner ] . dwellings . end ( ) ; + + it )
{ //+1 for each dwelling
if ( VLC - > creh - > creatures [ town - > basicCreatures [ level ] ] - > idNumber = = ( * it ) - > creatures [ 0 ] . second [ 0 ] )
+ + ret ;
}
2010-06-21 07:43:10 +03:00
}
2008-04-14 20:45:01 +03:00
if ( getHordeLevel ( 0 ) = = level )
if ( ( builtBuildings . find ( 18 ) ! = builtBuildings . end ( ) ) | | ( builtBuildings . find ( 19 ) ! = builtBuildings . end ( ) ) )
2010-05-02 21:20:26 +03:00
ret + = VLC - > creh - > creatures [ town - > basicCreatures [ level ] ] - > hordeGrowth ;
2008-04-14 20:45:01 +03:00
if ( getHordeLevel ( 1 ) = = level )
if ( ( builtBuildings . find ( 24 ) ! = builtBuildings . end ( ) ) | | ( builtBuildings . find ( 25 ) ! = builtBuildings . end ( ) ) )
2010-05-02 21:20:26 +03:00
ret + = VLC - > creh - > creatures [ town - > basicCreatures [ level ] ] - > hordeGrowth ;
2009-08-16 16:44:17 +03:00
//support for legs of legion etc.
if ( garrisonHero )
2010-05-02 21:20:26 +03:00
ret + = garrisonHero - > valOfBonuses ( Bonus : : CREATURE_GROWTH , level ) ;
2009-08-16 16:44:17 +03:00
if ( visitingHero )
2010-05-02 21:20:26 +03:00
ret + = visitingHero - > valOfBonuses ( Bonus : : CREATURE_GROWTH , level ) ;
2009-12-23 03:46:15 +02:00
if ( builtBuildings . find ( 26 ) ! = builtBuildings . end ( ) ) //grail - +50% to ALL growth
ret * = 1.5 ;
return ret ; //check CCastleInterface.cpp->CCastleInterface::CCreaInfo::clickRight if this one will be modified
2008-04-11 20:41:02 +03:00
}
2008-02-18 23:14:28 +02:00
int CGTownInstance : : dailyIncome ( ) const
{
int ret = 0 ;
if ( ( builtBuildings . find ( 26 ) ) ! = builtBuildings . end ( ) )
ret + = 5000 ;
if ( ( builtBuildings . find ( 13 ) ) ! = builtBuildings . end ( ) )
ret + = 4000 ;
else if ( ( builtBuildings . find ( 12 ) ) ! = builtBuildings . end ( ) )
ret + = 2000 ;
else if ( ( builtBuildings . find ( 11 ) ) ! = builtBuildings . end ( ) )
ret + = 1000 ;
else if ( ( builtBuildings . find ( 10 ) ) ! = builtBuildings . end ( ) )
ret + = 500 ;
return ret ;
}
2008-01-09 19:21:31 +02:00
bool CGTownInstance : : hasFort ( ) const
{
return ( builtBuildings . find ( 7 ) ) ! = builtBuildings . end ( ) ;
}
2008-02-05 05:56:45 +02:00
bool CGTownInstance : : hasCapitol ( ) const
{
return ( builtBuildings . find ( 13 ) ) ! = builtBuildings . end ( ) ;
}
2007-10-27 22:38:48 +03:00
CGTownInstance : : CGTownInstance ( )
2010-05-18 10:01:54 +03:00
: IShipyard ( this ) , IMarket ( this )
2007-10-27 22:38:48 +03:00
{
builded = - 1 ;
destroyed = - 1 ;
garrisonHero = NULL ;
town = NULL ;
2008-01-28 16:01:09 +02:00
visitingHero = NULL ;
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
{
for ( std : : vector < CGTownBuilding * > : : const_iterator i = bonusingBuildings . begin ( ) ; i ! = bonusingBuildings . end ( ) ; i + + )
delete * i ;
}
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
if ( subID = = 2 & & vstd : : contains ( builtBuildings , 22 ) ) //magic library in Tower
ret + + ;
return ret ;
2007-10-27 22:38:48 +03:00
}
2008-12-22 19:48:41 +02:00
2010-02-04 17:50:59 +02:00
int CGTownInstance : : defenceBonus ( int type ) const
{
int ret = 0 ;
switch ( type )
{
/*attack*/ case 0 :
if ( subID = = 6 & & vstd : : contains ( builtBuildings , 26 ) ) //Stronghold, grail
ret + = 12 ;
if ( subID = = 7 & & vstd : : contains ( builtBuildings , 26 ) ) //Fortress, grail
ret + = 10 ;
if ( subID = = 7 & & vstd : : contains ( builtBuildings , 22 ) ) //Fortress, Blood Obelisk
ret + = 2 ;
return ret ;
/*defence*/ case 1 :
if ( subID = = 7 & & vstd : : contains ( builtBuildings , 21 ) ) //Fortress, Glyphs of Fear
ret + = 2 ;
if ( subID = = 7 & & vstd : : contains ( builtBuildings , 26 ) ) //Fortress, Grail
ret + = 10 ;
return ret ;
/*spellpower*/ case 2 :
if ( subID = = 3 & & vstd : : contains ( builtBuildings , 21 ) ) //Inferno, Brimstone Clouds
ret + = 2 ;
if ( subID = = 5 & & vstd : : contains ( builtBuildings , 26 ) ) //Dungeon, Grail
ret + = 12 ;
return ret ;
/*knowledge*/ case 3 :
if ( subID = = 2 & & vstd : : contains ( builtBuildings , 26 ) ) //Tower, Grail
ret + = 15 ;
return ret ;
}
return 0 ; //Why we are here? wrong type?
}
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
{
2008-12-22 19:48:41 +02:00
if ( getOwner ( ) ! = h - > getOwner ( ) )
{
2009-08-22 16:59:15 +03:00
//TODO ally check
2010-05-02 21:20:26 +03:00
if ( stacksCount ( ) > 0 | | visitingHero )
2009-08-22 16:59:15 +03:00
{
const CGHeroInstance * defendingHero = NULL ;
if ( visitingHero )
defendingHero = visitingHero ;
else if ( garrisonHero )
defendingHero = garrisonHero ;
const CArmedInstance * defendingArmy = this ;
if ( defendingHero )
defendingArmy = defendingHero ;
bool outsideTown = ( defendingHero = = visitingHero & & garrisonHero ) ;
cb - > startBattleI ( h , defendingArmy , getSightCenter ( ) , h , defendingHero , false , boost : : bind ( & CGTownInstance : : fightOver , this , h , _1 ) , ( outsideTown ? NULL : this ) ) ;
}
else
{
2009-09-22 19:12:33 +03:00
cb - > setOwner ( id , h - > tempOwner ) ;
2010-02-28 08:36:51 +02:00
removeCapitols ( h - > getOwner ( ) ) ;
2009-10-06 09:15:56 +03:00
cb - > heroVisitCastle ( id , h - > id ) ;
2009-08-22 16:59:15 +03:00
}
2008-12-22 19:48:41 +02:00
}
2009-10-06 09:15:56 +03:00
else
cb - > heroVisitCastle ( id , h - > id ) ;
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
{
2008-12-22 19:48:41 +02:00
cb - > stopHeroVisitCastle ( id , h - > id ) ;
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 ;
2009-07-09 22:15:22 +03:00
hoverName = name + " , " + town - > Name ( ) ;
2009-07-06 22:41:27 +03:00
2010-07-10 19:50:23 +03:00
if ( subID = = 5 )
creatures . resize ( CREATURES_PER_TOWN + 1 ) ; //extra dwelling for Dungeon
else
creatures . resize ( CREATURES_PER_TOWN ) ;
2009-07-06 22:41:27 +03:00
for ( int i = 0 ; i < CREATURES_PER_TOWN ; i + + )
{
if ( creatureDwelling ( i , false ) )
creatures [ i ] . second . push_back ( town - > basicCreatures [ i ] ) ;
if ( creatureDwelling ( i , true ) )
creatures [ i ] . second . push_back ( town - > upgradedCreatures [ i ] ) ;
}
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 :
bonusingBuildings . push_back ( new COPWBonus ( 21 , this ) ) ; //Stables
break ;
2010-07-10 19:50:23 +03:00
case 5 :
bonusingBuildings . push_back ( new COPWBonus ( 21 , this ) ) ; //Vortex
case 2 : case 3 : case 6 :
2009-10-05 19:38:54 +03:00
bonusingBuildings . push_back ( new CTownBonus ( 23 , this ) ) ;
2009-08-23 18:02:21 +03:00
break ;
case 7 :
2009-10-05 19:38:54 +03:00
bonusingBuildings . push_back ( new CTownBonus ( 17 , this ) ) ;
2009-08-23 18:02:21 +03:00
break ;
2010-06-13 16:59:59 +03:00
}
//add special bonuses from buildings
if ( subID = = 4 & & vstd : : contains ( builtBuildings , 17 ) )
{
bonuses . push_back ( Bonus ( Bonus : : PERMANENT , Bonus : : DARKNESS , Bonus : : TOWN_STRUCTURE , 20 , 17 ) ) ;
2009-08-23 18:02:21 +03:00
}
2008-12-22 19:48:41 +02:00
}
2009-10-06 10:55:39 +03:00
void CGTownInstance : : newTurn ( ) const
{
2010-01-28 18:15:46 +02:00
if ( cb - > getDate ( 1 ) = = 1 ) //reset on new week
2009-10-06 10:55:39 +03:00
{
2010-02-04 17:50:59 +02:00
if ( vstd : : contains ( builtBuildings , 17 ) & & subID = = 1 & & cb - > getDate ( 0 ) ! = 1 & & ( tempOwner < PLAYER_LIMIT ) ) //give resources for Rampart, Mystic Pond
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
cb - > giveResource ( tempOwner , resID , resVal ) ;
cb - > setObjProperty ( id , 14 , resID ) ;
cb - > setObjProperty ( id , 15 , resVal ) ;
}
if ( subID = = 5 )
for ( std : : vector < CGTownBuilding * > : : const_iterator i = bonusingBuildings . begin ( ) ; i ! = bonusingBuildings . end ( ) ; i + + )
2010-01-01 14:15:20 +02:00
{
if ( ( * i ) - > ID = = 21 )
cb - > setObjProperty ( id , 12 , ( * i ) - > id ) ; //reset visitors for Mana Vortex
}
2010-06-29 12:59:14 +03:00
if ( tempOwner = = NEUTRAL_PLAYER ) //garrison growth for neutral towns
{
TSlots slt = Slots ( ) ; //meh, waste of time
std : : vector < ui8 > nativeCrits ; //slots
for ( TSlots : : const_iterator it = slt . begin ( ) ; it ! = slt . end ( ) ; it + + )
{
if ( it - > second . type - > faction = = subID ) //native
{
nativeCrits . push_back ( it - > first ) ; //collect matching slots
}
}
if ( nativeCrits . size ( ) )
{
int pos = nativeCrits [ rand ( ) % nativeCrits . size ( ) ] ;
if ( rand ( ) % 100 < 90 | | slt [ pos ] . type - > upgrades . empty ( ) ) //increase number if no upgrade avaliable
{
SetGarrisons sg ;
sg . garrs [ id ] = getArmy ( ) ;
sg . garrs [ id ] . slots [ pos ] . count + = slt [ pos ] . type - > growth ;
cb - > sendAndApply ( & sg ) ;
}
else //upgrade
{
SetGarrisons sg ; //somewhat better upgrade pack would come in handy
sg . garrs [ id ] = getArmy ( ) ;
sg . garrs [ id ] . setCreature ( pos , * slt [ pos ] . type - > upgrades . begin ( ) , slt [ pos ] . count ) ;
cb - > sendAndApply ( & sg ) ;
}
}
if ( ( stacksCount ( ) < ARMY_SIZE & & rand ( ) % 100 < 25 ) | | slt . empty ( ) ) //add new stack
{
int n , i = rand ( ) % std : : min ( ARMY_SIZE , cb - > getDate ( 3 ) < < 1 ) ;
{ //no lower tiers or above current month
if ( n = getSlotFor ( town - > basicCreatures [ i ] , ARMY_SIZE ) ) ;
{
SetGarrisons sg ;
sg . garrs [ id ] = getArmy ( ) ;
if ( slotEmpty ( n ) )
sg . garrs [ id ] . setCreature ( n , town - > basicCreatures [ i ] , creatureGrowth ( i ) ) ; //if the stack is not yet present
else
sg . garrs [ id ] . addToSlot ( n , town - > basicCreatures [ i ] , creatureGrowth ( i ) ) ; //add to existing
cb - > sendAndApply ( & sg ) ;
}
}
}
}
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
{
2010-05-02 21:20:26 +03:00
return stacksCount ( ) ? 1 < < tempOwner : ALL_PLAYERS ; //if there is garrison army, castle be entered only by owner //TODO: allies
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
}
2009-08-22 16:59:15 +03:00
void CGTownInstance : : fightOver ( const CGHeroInstance * h , BattleResult * result ) const
{
if ( result - > winner = = 0 )
{
2010-06-07 08:28:12 +03:00
if ( hasBonusOfType ( Bonus : : DARKNESS ) )
{
//TODO: Make some 'change owner' function for bonus, or bonuses independent of player
/*
RemoveBonus rb ( RemoveBonus : : PLAYER ) ;
rb . whoID = getOwner ( ) ;
rb . source = Bonus : : TOWN_STRUCTURE ;
rb . id = id ;
cb - > sendAndApply ( & rb ) ;
GiveBonus gb ( GiveBonus : : PLAYER ) ;
gb . bonus . type = Bonus : : DARKNESS ;
gb . bonus . val = 20 ;
gb . id = h - > tempOwner ;
gb . bonus . duration = Bonus : : PERMANENT ;
gb . bonus . source = Bonus : : TOWN_STRUCTURE ;
gb . bonus . id = id ;
cb - > sendAndApply ( & gb ) ;
*/
}
2010-02-28 08:36:51 +02:00
removeCapitols ( h - > getOwner ( ) ) ;
2009-09-23 15:42:14 +03:00
cb - > setOwner ( id , h - > tempOwner ) ; //give control after checkout is done
2010-06-03 09:18:12 +03:00
FoWChange fw ;
fw . player = h - > tempOwner ;
fw . mode = 1 ;
getSightTiles ( fw . tiles ) ; //update visibility for castle structures
cb - > sendAndApply ( & fw ) ;
2010-06-07 08:28:12 +03:00
2009-08-22 16:59:15 +03:00
}
}
2009-09-23 15:05:33 +03:00
2010-02-28 08:36:51 +02:00
void CGTownInstance : : removeCapitols ( ui8 owner ) const
2009-09-23 15:42:14 +03:00
{
2010-02-28 08:36:51 +02:00
if ( hasCapitol ( ) ) // search if there's an older capitol
2009-09-23 15:42:14 +03:00
{
2009-10-06 09:15:56 +03:00
PlayerState * state = cb - > gameState ( ) - > getPlayer ( owner ) ; //get all towns owned by player
2009-09-23 15:42:14 +03:00
for ( std : : vector < CGTownInstance * > : : const_iterator i = state - > towns . begin ( ) ; i < state - > towns . end ( ) ; + + i )
{
if ( * i ! = this & & ( * i ) - > hasCapitol ( ) )
{
2010-02-28 08:36:51 +02:00
RazeStructures rs ;
rs . tid = id ;
rs . bid . insert ( 13 ) ;
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
{
2010-05-02 21:20:26 +03:00
const CCreature * c = VLC - > creh - > creatures [ town - > basicCreatures . front ( ) ] ;
2010-02-13 06:47:31 +02:00
if ( c - > isGood ( ) )
return 1 ;
else if ( c - > isEvil ( ) )
return 0 ;
else //neutral
return 2 ;
2010-02-01 19:07:46 +02:00
}
2010-05-02 21:20:26 +03:00
void CGTownInstance : : getParents ( TCNodes & out , const CBonusSystemNode * root /*= NULL*/ ) const
{
CArmedInstance : : getParents ( out , root ) ;
if ( root = = this & & visitingHero & & visitingHero ! = root )
out . insert ( visitingHero ) ;
}
void CGTownInstance : : getBonuses ( BonusList & out , const CSelector & selector , const CBonusSystemNode * root /*= NULL*/ ) const
{
CArmedInstance : : getBonuses ( out , selector , root ) ;
//TODO eliminate by moving structures effects to bonus system
if ( Selector : : matchesType ( selector , Bonus : : LUCK ) )
{
if ( subID = = 1 & & vstd : : contains ( builtBuildings , 21 ) ) //rampart, fountain of fortune
out . push_back ( Bonus ( Bonus : : PERMANENT , Bonus : : LUCK , Bonus : : TOWN_STRUCTURE , + 2 , 21 , VLC - > generaltexth - > buildings [ 1 ] [ 21 ] . first + " +2 " ) ) ;
}
if ( Selector : : matchesType ( selector , Bonus : : MORALE ) )
{
if ( subID = = 0 & & vstd : : contains ( builtBuildings , 22 ) ) //castle, brotherhood of sword built
out . push_back ( Bonus ( Bonus : : PERMANENT , Bonus : : MORALE , Bonus : : TOWN_STRUCTURE , + 2 , 22 , VLC - > generaltexth - > buildings [ 0 ] [ 22 ] . first + " +2 " ) ) ;
else if ( vstd : : contains ( builtBuildings , 5 ) ) //tavern is built
out . push_back ( Bonus ( Bonus : : PERMANENT , Bonus : : MORALE , Bonus : : TOWN_STRUCTURE , + 1 , 5 , VLC - > generaltexth - > buildings [ 0 ] [ 5 ] . first + " +1 " ) ) ;
}
}
2010-05-18 10:01:54 +03:00
int CGTownInstance : : getMarketEfficiency ( ) const
{
if ( ! vstd : : contains ( builtBuildings , 14 ) )
return 0 ;
const PlayerState * p = cb - > getPlayerState ( tempOwner ) ;
assert ( p ) ;
int marketCount = 0 ;
BOOST_FOREACH ( const CGTownInstance * t , p - > towns )
if ( vstd : : contains ( t - > builtBuildings , 14 ) )
marketCount + + ;
return marketCount ;
}
bool CGTownInstance : : allowsTrade ( EMarketMode mode ) const
{
switch ( mode )
{
case RESOURCE_RESOURCE :
case RESOURCE_PLAYER :
return vstd : : contains ( builtBuildings , 14 ) ; // marketplace
case ARTIFACT_RESOURCE :
2010-07-20 09:05:45 +03:00
case RESOURCE_ARTIFACT :
2010-05-18 10:01:54 +03:00
return ( subID = = 2 | | subID = = 5 | | subID = = 8 ) & & vstd : : contains ( builtBuildings , 17 ) ; //artifact merchants
case CREATURE_RESOURCE :
return subID = = 6 & & vstd : : contains ( builtBuildings , 21 ) ; //Freelancer's guild
2010-07-03 15:00:53 +03:00
case CREATURE_UNDEAD :
return subID = = 4 & & vstd : : contains ( builtBuildings , 22 ) ; //Skeleton transformer
2010-07-20 17:08:13 +03:00
case RESOURCE_SKILL :
return subID = = 8 & & vstd : : contains ( builtBuildings , 21 ) ; //Magic University
2010-05-18 10:01:54 +03:00
default :
assert ( 0 ) ;
return false ;
}
}
2010-06-27 19:03:01 +03:00
std : : vector < int > CGTownInstance : : availableItemsIds ( EMarketMode mode ) const
{
if ( mode = = RESOURCE_ARTIFACT )
{
std : : vector < int > ret ;
BOOST_FOREACH ( const CArtifact * a , merchantArtifacts )
if ( a )
ret . push_back ( a - > id ) ;
else
ret . push_back ( - 1 ) ;
return ret ;
}
2010-07-20 17:08:13 +03:00
else if ( mode = = RESOURCE_SKILL )
{
return universitySkills ;
}
2010-06-27 19:03:01 +03:00
else
return IMarket : : availableItemsIds ( mode ) ;
}
2008-12-27 03:01:59 +02:00
void CGVisitableOPH : : onHeroVisit ( const CGHeroInstance * h ) const
2008-12-22 19:48:41 +02:00
{
if ( visitors . find ( h - > id ) = = visitors . end ( ) )
2008-10-26 22:58:34 +02:00
{
2008-12-22 19:48:41 +02:00
onNAHeroVisit ( h - > id , false ) ;
2009-04-11 04:32:50 +03:00
switch ( ID )
{
case 102 : //tree
case 4 : //arena
case 41 : //library
case 47 : //School of Magic
case 107 : //School of War
break ;
default :
2010-05-02 21:20:26 +03:00
cb - > setObjProperty ( id , ObjProperty : : VISITORS , h - > id ) ; //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
{
2008-12-22 19:48:41 +02:00
onNAHeroVisit ( h - > id , 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 ( )
{
if ( ID = = 102 )
ttype = ran ( ) % 3 ;
else
ttype = - 1 ;
}
2008-10-26 22:58:34 +02:00
2010-07-13 22:55:13 +03:00
void CGVisitableOPH : : treeSelected ( int heroID , int resType , int resVal , expType expVal , 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
{
2008-12-22 19:48:41 +02:00
cb - > giveResource ( cb - > getOwner ( heroID ) , resType , - resVal ) ; //take resource
cb - > changePrimSkill ( heroID , 4 , expVal ) ; //give exp
2010-05-02 21:20:26 +03:00
cb - > setObjProperty ( id , ObjProperty : : VISITORS , heroID ) ; //add to the visitors
2008-10-26 22:58:34 +02:00
}
2008-12-22 19:48:41 +02:00
}
2008-12-27 03:01:59 +02:00
void CGVisitableOPH : : onNAHeroVisit ( int heroID , bool alreadyVisited ) const
2008-12-22 19:48:41 +02:00
{
2010-07-13 22:55:13 +03:00
int id = 0 , subid = 0 , ot = 0 , sound = 0 ;
expType val = 1 ;
2008-12-22 19:48:41 +02:00
switch ( ID )
2008-11-14 20:18:13 +02:00
{
2009-04-24 00:09:10 +03:00
case 4 : //arena
sound = soundBase : : NOMAD ;
2009-01-11 00:08:18 +02:00
ot = 0 ;
break ;
2009-04-24 00:09:10 +03:00
case 51 : //mercenary camp
sound = soundBase : : NOMAD ;
2008-12-22 19:48:41 +02:00
subid = 0 ;
ot = 80 ;
break ;
2009-04-24 00:09:10 +03:00
case 23 : //marletto tower
sound = soundBase : : NOMAD ;
2008-12-22 19:48:41 +02:00
subid = 1 ;
ot = 39 ;
break ;
case 61 :
2009-04-24 00:09:10 +03:00
sound = soundBase : : gazebo ;
2008-12-22 19:48:41 +02:00
subid = 2 ;
ot = 100 ;
break ;
case 32 :
2009-04-24 00:09:10 +03:00
sound = soundBase : : GETPROTECTION ;
2008-12-22 19:48:41 +02:00
subid = 3 ;
ot = 59 ;
break ;
case 100 :
2009-04-24 00:09:10 +03:00
sound = soundBase : : gazebo ;
2008-12-22 19:48:41 +02:00
id = 5 ;
ot = 143 ;
val = 1000 ;
break ;
case 102 :
2009-04-24 00:09:10 +03:00
sound = soundBase : : gazebo ;
2008-12-22 19:48:41 +02:00
id = 5 ;
subid = 1 ;
ot = 146 ;
val = 1 ;
break ;
2009-02-01 16:11:41 +02:00
case 41 :
2009-04-24 00:09:10 +03:00
sound = soundBase : : gazebo ;
2009-02-01 16:11:41 +02:00
ot = 66 ;
break ;
2009-04-11 04:32:50 +03:00
case 47 : //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 ;
case 107 : //School of War
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
{
2009-01-11 00:08:18 +02:00
case 4 : //arena
{
2009-04-11 04:32:50 +03:00
BlockingDialog sd ( false , true ) ;
2009-04-24 00:09:10 +03:00
sd . soundID = sound ;
2009-01-11 00:08:18 +02:00
sd . text < < std : : pair < ui8 , ui32 > ( 11 , ot ) ;
sd . components . push_back ( Component ( 0 , 0 , 2 , 0 ) ) ;
sd . components . push_back ( Component ( 0 , 1 , 2 , 0 ) ) ;
sd . player = cb - > getOwner ( heroID ) ;
2009-04-11 04:32:50 +03:00
cb - > showBlockingDialog ( & sd , boost : : bind ( & CGVisitableOPH : : arenaSelected , this , heroID , _1 ) ) ;
2009-01-11 00:08:18 +02:00
return ;
}
2008-12-22 19:48:41 +02:00
case 51 :
case 23 :
case 61 :
case 32 :
2008-10-26 22:58:34 +02:00
{
2008-12-22 19:48:41 +02:00
cb - > changePrimSkill ( heroID , subid , val ) ;
InfoWindow iw ;
2009-04-24 00:09:10 +03:00
iw . soundID = sound ;
2008-12-22 19:48:41 +02:00
iw . components . push_back ( Component ( 0 , subid , val , 0 ) ) ;
iw . text < < std : : pair < ui8 , ui32 > ( 11 , ot ) ;
iw . player = cb - > getOwner ( heroID ) ;
cb - > showInfoDialog ( & iw ) ;
break ;
}
case 100 : //give exp
{
2010-07-26 01:47:59 +03:00
const CGHeroInstance * h = cb - > getHero ( heroID ) ;
val = val * ( 100 + h - > getSecSkillLevel ( 21 ) * 5 ) / 100.0f ;
2008-12-22 19:48:41 +02:00
InfoWindow iw ;
2009-04-24 00:09:10 +03:00
iw . soundID = sound ;
2008-12-22 19:48:41 +02:00
iw . components . push_back ( Component ( id , subid , val , 0 ) ) ;
iw . player = cb - > getOwner ( heroID ) ;
iw . text < < std : : pair < ui8 , ui32 > ( 11 , ot ) ;
2009-04-22 21:48:56 +03:00
iw . soundID = soundBase : : gazebo ;
2008-12-22 19:48:41 +02:00
cb - > showInfoDialog ( & iw ) ;
cb - > changePrimSkill ( heroID , 4 , val ) ;
break ;
}
2009-04-11 04:32:50 +03:00
case 102 : //tree
2008-12-22 19:48:41 +02:00
{
const CGHeroInstance * h = cb - > getHero ( heroID ) ;
val = VLC - > heroh - > reqExp ( h - > level + val ) - VLC - > heroh - > reqExp ( h - > level ) ;
if ( ! ttype )
2008-10-26 22:58:34 +02:00
{
2010-05-02 21:20:26 +03:00
cb - > setObjProperty ( this - > id , ObjProperty : : VISITORS , heroID ) ; //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 ;
2008-12-22 19:48:41 +02:00
iw . components . push_back ( Component ( id , subid , 1 , 0 ) ) ;
iw . player = cb - > getOwner ( heroID ) ;
iw . text < < std : : pair < ui8 , ui32 > ( 11 , 148 ) ;
cb - > showInfoDialog ( & iw ) ;
cb - > changePrimSkill ( heroID , 4 , val ) ;
2008-10-26 22:58:34 +02:00
break ;
}
2008-12-22 19:48:41 +02:00
else
{
2010-07-13 22:55:13 +03:00
ui32 res ;
expType resval ;
2008-12-22 19:48:41 +02:00
if ( ttype = = 1 )
{
res = 6 ;
resval = 2000 ;
ot = 149 ;
}
else
{
res = 5 ;
resval = 10 ;
ot = 151 ;
}
if ( cb - > getResource ( h - > tempOwner , res ) < resval ) //not enough resources
{
ot + + ;
InfoWindow iw ;
2009-04-24 00:09:10 +03:00
iw . soundID = sound ;
2008-12-22 19:48:41 +02:00
iw . player = h - > tempOwner ;
iw . text < < std : : pair < ui8 , ui32 > ( 11 , ot ) ;
cb - > showInfoDialog ( & iw ) ;
return ;
}
2009-10-03 14:16:42 +03:00
BlockingDialog sd ( true , false ) ;
2009-04-24 00:09:10 +03:00
sd . soundID = sound ;
2008-12-22 19:48:41 +02:00
sd . player = cb - > getOwner ( heroID ) ;
sd . text < < std : : pair < ui8 , ui32 > ( 11 , ot ) ;
2009-10-03 14:16:42 +03:00
sd . components . push_back ( Component ( Component : : RESOURCE , res , resval , 0 ) ) ;
2009-04-11 04:32:50 +03:00
cb - > showBlockingDialog ( & sd , boost : : bind ( & CGVisitableOPH : : treeSelected , this , heroID , res , resval , val , _1 ) ) ;
2008-12-22 19:48:41 +02:00
}
break ;
2008-10-26 22:58:34 +02:00
}
2009-04-11 04:32:50 +03:00
case 41 : //library of enlightenment
2009-02-01 16:11:41 +02:00
{
const CGHeroInstance * h = cb - > getHero ( heroID ) ;
if ( h - > level < 10 - 2 * h - > getSecSkillLevel ( 4 ) ) //not enough level
{
InfoWindow iw ;
2009-04-24 00:09:10 +03:00
iw . soundID = sound ;
2009-02-01 16:11:41 +02:00
iw . player = cb - > getOwner ( heroID ) ;
iw . text < < std : : pair < ui8 , ui32 > ( 11 , 68 ) ;
cb - > showInfoDialog ( & iw ) ;
}
else
{
2010-05-02 21:20:26 +03:00
cb - > setObjProperty ( this - > id , ObjProperty : : VISITORS , heroID ) ; //add to the visitors
2009-02-01 16:11:41 +02:00
cb - > changePrimSkill ( heroID , 0 , 2 ) ;
cb - > changePrimSkill ( heroID , 1 , 2 ) ;
cb - > changePrimSkill ( heroID , 2 , 2 ) ;
cb - > changePrimSkill ( heroID , 3 , 2 ) ;
InfoWindow iw ;
2009-04-24 00:09:10 +03:00
iw . soundID = sound ;
2009-02-01 16:11:41 +02:00
iw . player = cb - > getOwner ( heroID ) ;
iw . text < < std : : pair < ui8 , ui32 > ( 11 , 66 ) ;
cb - > showInfoDialog ( & iw ) ;
}
break ;
}
2009-04-11 04:32:50 +03:00
case 47 : //School of Magic
case 107 : //School of War
{
int skill = ( ID = = 47 ? 2 : 0 ) ;
if ( cb - > getResource ( cb - > getOwner ( heroID ) , 6 ) < 1000 ) //not enough resources
{
InfoWindow iw ;
2009-04-24 00:09:10 +03:00
iw . soundID = sound ;
2009-04-11 04:32:50 +03:00
iw . player = cb - > getOwner ( heroID ) ;
iw . text < < std : : pair < ui8 , ui32 > ( MetaString : : ADVOB_TXT , ot + 2 ) ;
cb - > showInfoDialog ( & iw ) ;
}
else
{
BlockingDialog sd ( true , true ) ;
2009-04-24 00:09:10 +03:00
sd . soundID = sound ;
2009-04-11 04:32:50 +03:00
sd . player = cb - > getOwner ( heroID ) ;
sd . text < < std : : pair < ui8 , ui32 > ( 11 , ot ) ;
sd . components . push_back ( Component ( Component : : PRIM_SKILL , skill , + 1 , 0 ) ) ;
sd . components . push_back ( Component ( Component : : PRIM_SKILL , skill + 1 , + 1 , 0 ) ) ;
cb - > showBlockingDialog ( & sd , boost : : bind ( & CGVisitableOPH : : schoolSelected , this , heroID , _1 ) ) ;
}
}
break ;
2008-10-26 22:58:34 +02:00
}
}
2008-12-22 19:48:41 +02:00
else
{
ot + + ;
InfoWindow iw ;
2009-04-24 00:09:10 +03:00
iw . soundID = sound ;
2008-12-22 19:48:41 +02:00
iw . player = cb - > getOwner ( heroID ) ;
iw . text < < std : : pair < ui8 , ui32 > ( 11 , ot ) ;
cb - > showInfoDialog ( & iw ) ;
}
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 )
{
2009-01-11 00:08:18 +02:00
case 4 :
pom = - 1 ;
break ;
2008-12-22 19:48:41 +02:00
case 51 :
pom = 8 ;
break ;
case 23 :
pom = 7 ;
break ;
case 61 :
pom = 11 ;
break ;
case 32 :
pom = 4 ;
break ;
case 100 :
pom = 5 ;
break ;
case 102 :
pom = 18 ;
break ;
2009-02-01 16:11:41 +02:00
case 41 :
break ;
2009-04-11 04:32:50 +03:00
case 47 : //School of Magic
pom = 9 ;
break ;
case 107 : //School of War
pom = 10 ;
break ;
2008-12-22 19:48:41 +02:00
default :
2009-01-11 00:08:18 +02:00
throw std : : string ( " 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 ] ) ;
2008-12-22 19:48:41 +02:00
const CGHeroInstance * h = cb - > getSelectedHero ( cb - > getCurrentPlayer ( ) ) ;
if ( h )
{
2010-07-31 03:26:34 +03:00
hoverName + = " \n \n " ;
2008-12-22 19:48:41 +02:00
hoverName + = ( vstd : : contains ( visitors , h - > id ) )
2008-12-27 03:01:59 +02:00
? ( VLC - > generaltexth - > allTexts [ 352 ] ) //visited
: ( VLC - > generaltexth - > allTexts [ 353 ] ) ; //not visited
2008-12-22 19:48:41 +02:00
}
return hoverName ;
2007-10-27 22:38:48 +03:00
}
2009-01-11 00:08:18 +02:00
void CGVisitableOPH : : arenaSelected ( int heroID , int primSkill ) const
{
2010-05-02 21:20:26 +03:00
cb - > setObjProperty ( id , ObjProperty : : VISITORS , heroID ) ; //add to the visitors
2009-04-11 04:32:50 +03:00
cb - > changePrimSkill ( heroID , 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 )
2009-02-20 14:39:27 +02:00
visitors . insert ( val ) ;
}
2009-04-11 04:32:50 +03:00
void CGVisitableOPH : : schoolSelected ( int heroID , ui32 which ) const
{
if ( ! which ) //player refused to pay
return ;
int base = ( ID = = 47 ? 2 : 0 ) ;
2010-05-02 21:20:26 +03:00
cb - > setObjProperty ( id , ObjProperty : : VISITORS , heroID ) ; //add to the visitors
2009-04-11 04:32:50 +03:00
cb - > giveResource ( cb - > getOwner ( heroID ) , 6 , - 1000 ) ; //take 1000 gold
cb - > changePrimSkill ( heroID , base + which - 1 , + 1 ) ; //give appropriate skill
}
2009-10-05 19:38:54 +03:00
COPWBonus : : COPWBonus ( int index , CGTownInstance * TOWN )
{
ID = index ;
town = TOWN ;
id = town - > bonusingBuildings . size ( ) ;
}
void COPWBonus : : setProperty ( ui8 what , ui32 val )
{
switch ( what )
{
case 4 :
visitors . insert ( val ) ;
break ;
2009-10-06 10:55:39 +03:00
case 12 :
2009-10-05 19:38:54 +03:00
visitors . clear ( ) ;
break ;
}
}
void COPWBonus : : onHeroVisit ( const CGHeroInstance * h ) const
{
int heroID = h - > id ;
if ( town - > builtBuildings . find ( ID ) ! = town - > builtBuildings . end ( ) )
{
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
{
2009-10-06 10:55:39 +03:00
case 0 : //Stables
2010-05-02 21:20:26 +03:00
if ( ! h - > hasBonusFrom ( Bonus : : OBJECT , 94 ) ) //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 ] ) ;
2010-02-10 04:56:00 +02:00
gb . id = heroID ;
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 ;
case 5 : //Mana Vortex
2010-01-01 14:15:20 +02:00
if ( visitors . empty ( ) & & h - > mana < = h - > manaLimit ( ) )
2009-10-06 10:55:39 +03:00
{
cb - > setManaPoints ( heroID , 2 * h - > manaLimit ( ) ) ;
2010-05-02 21:20:26 +03:00
cb - > setObjProperty ( 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 ) ;
2009-10-06 10:55:39 +03:00
cb - > setObjProperty ( town - > id , 11 , id ) ; //add to visitors
2009-10-05 19:38:54 +03:00
}
break ;
}
}
}
2009-08-23 18:02:21 +03:00
CTownBonus : : CTownBonus ( int index , CGTownInstance * TOWN )
{
ID = index ;
town = TOWN ;
2009-09-21 12:00:33 +03:00
id = town - > bonusingBuildings . size ( ) ;
}
void CTownBonus : : setProperty ( ui8 what , ui32 val )
{
if ( what = = 4 )
visitors . insert ( val ) ;
2009-08-23 18:02:21 +03:00
}
void CTownBonus : : onHeroVisit ( const CGHeroInstance * h ) const
{
int heroID = h - > id ;
if ( ( town - > builtBuildings . find ( ID ) ! = town - > builtBuildings . end ( ) ) & & ( visitors . find ( heroID ) = = visitors . end ( ) ) )
{
InfoWindow iw ;
2009-10-06 10:55:39 +03:00
int what , val , mid ;
2009-08-23 18:02:21 +03:00
switch ( ID )
{
case 23 :
2009-09-21 12:00:33 +03:00
switch ( town - > subID )
2009-08-23 18:02:21 +03:00
{
case 2 : //wall
2009-10-05 14:28:49 +03:00
what = 3 ;
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 ;
case 3 : //order of fire
2009-10-05 14:28:49 +03:00
what = 2 ;
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 ;
case 6 : //hall of valhalla
2009-10-05 14:28:49 +03:00
what = 0 ;
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 ;
case 5 : //academy of battle scholars
2009-10-05 14:28:49 +03:00
what = 4 ;
2010-07-26 01:47:59 +03:00
val = 1000 * ( 100 + h - > getSecSkillLevel ( 21 ) * 5 ) / 100.0f ;
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 ;
case 17 :
2009-09-21 12:00:33 +03:00
switch ( town - > subID )
2009-08-23 18:02:21 +03:00
{
case 7 : //cage of warlords
2009-10-05 14:28:49 +03:00
what = 1 ;
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 ;
}
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 ) ;
2009-10-05 14:28:49 +03:00
cb - > changePrimSkill ( heroID , what , val ) ;
2009-12-30 22:49:10 +02:00
if ( town - > visitingHero = = h )
cb - > setObjProperty ( town - > id , 11 , id ) ; //add to visitors
else
cb - > setObjProperty ( town - > id , 13 , id ) ; //then it must be garrisoned hero
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
{
2010-06-28 16:33:05 +03:00
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 ) ;
ms . toString ( hoverName ) ;
2010-07-07 05:29:07 +03:00
if ( const CGHeroInstance * selHero = cb - > getSelectedHero ( cb - > getCurrentPlayer ( ) ) )
{
hoverName + = " \n \n Threat: " ;
float ratio = ( ( float ) getArmyStrength ( ) / selHero - > getTotalStrength ( ) ) ;
if ( ratio < 0.1 ) hoverName + = " Effortless " ;
else if ( ratio < 0.25 ) hoverName + = " Very Weak " ;
else if ( ratio < 0.6 ) hoverName + = " Weak " ;
else if ( ratio < 0.9 ) hoverName + = " A bit weaker " ;
else if ( ratio < 1.1 ) hoverName + = " Equal " ;
else if ( ratio < 1.3 ) hoverName + = " A bit stronger " ;
else if ( ratio < 1.8 ) hoverName + = " Strong " ;
else if ( ratio < 2.5 ) hoverName + = " Very Strong " ;
else if ( ratio < 4 ) hoverName + = " Challenging " ;
else if ( ratio < 8 ) hoverName + = " Overpowering " ;
else if ( ratio < 20 ) hoverName + = " Deadly " ;
else hoverName + = " Impossible " ;
}
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...
{
case - 2 : //fight
fight ( h ) ;
break ;
case - 1 : //flee
{
flee ( h ) ;
break ;
}
case 0 : //join for free
{
BlockingDialog ynd ( true , false ) ;
ynd . player = h - > tempOwner ;
2009-07-09 22:15:22 +03:00
ynd . text < < std : : pair < ui8 , ui32 > ( MetaString : : ADVOB_TXT , 86 ) ;
ynd . text . addReplacement ( MetaString : : CRE_PL_NAMES , subID ) ;
2009-04-12 04:48:50 +03:00
cb - > showBlockingDialog ( & ynd , boost : : bind ( & CGCreature : : joinDecision , this , h , 0 , _1 ) ) ;
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 ] ;
2010-05-02 21:20:26 +03:00
boost : : algorithm : : replace_first ( tmp , " %d " , boost : : lexical_cast < std : : string > ( slots . find ( 0 ) - > second . count ) ) ;
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 ;
cb - > showBlockingDialog ( & ynd , boost : : bind ( & CGCreature : : joinDecision , this , h , action , _1 ) ) ;
break ;
}
}
2008-11-28 03:36:34 +02:00
}
2008-09-12 11:51:46 +03:00
2008-12-27 03:01:59 +02:00
void CGCreature : : endBattle ( BattleResult * result ) const
2008-09-12 11:51:46 +03:00
{
2008-12-22 19:48:41 +02:00
if ( result - > winner = = 0 )
{
cb - > removeObject ( id ) ;
}
else
{
2009-07-21 02:34:06 +03:00
//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;
2010-05-02 21:20:26 +03:00
//cb->setAmount(id, slots.find(0)->second.second - killedAmount);
2009-07-21 02:34:06 +03:00
2010-06-28 16:33:05 +03:00
/*
2008-12-27 03:01:59 +02:00
MetaString ms ;
2010-05-02 21:20:26 +03:00
int pom = slots . find ( 0 ) - > second . getQuantityID ( ) ;
2008-12-27 03:01:59 +02:00
pom = 174 + 3 * pom + 1 ;
ms < < std : : pair < ui8 , ui32 > ( 6 , pom ) < < " " < < std : : pair < ui8 , ui32 > ( 7 , subID ) ;
cb - > setHoverName ( id , & ms ) ;
2010-06-26 15:57:16 +03:00
cb - > setObjProperty ( id , 11 , slots . begin ( ) - > second . count * 1000 ) ;
2010-06-28 16:33:05 +03:00
*/
2008-12-22 19:48:41 +02:00
}
2008-09-12 11:51:46 +03:00
}
2008-11-15 02:55:19 +02: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 :
character = 0 ;
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 ;
}
2010-05-02 21:20:26 +03:00
slots [ 0 ] . setType ( subID ) ;
si32 & amount = slots [ 0 ] . count ;
CCreature & c = * VLC - > creh - > creatures [ subID ] ;
2008-12-22 19:48:41 +02:00
if ( ! amount )
if ( c . ammMax = = c . ammMin )
amount = c . ammMax ;
else
amount = c . ammMin + ( ran ( ) % ( c . ammMax - c . ammMin ) ) ;
2010-07-07 15:51:28 +03:00
2010-06-26 15:57:16 +03:00
temppower = slots [ 0 ] . count * 1000 ;
}
void CGCreature : : newTurn ( ) const
{ //Works only for stacks of single type of size up to 2 millions
2010-07-17 16:11:12 +03:00
if ( slots . begin ( ) - > second . count < CREEP_SIZE & & cb - > getDate ( 1 ) = = 1 & & cb - > getDate ( 0 ) > 1 )
2010-06-26 15:57:16 +03:00
{
ui32 power = temppower * ( 100 + WEEKLY_GROWTH ) / 100 ;
cb - > setObjProperty ( id , 10 , std : : min ( power / 1000 , ( ui32 ) CREEP_SIZE ) ) ; //set new amount
cb - > setObjProperty ( id , 11 , power ) ; //increase temppower
}
}
void CGCreature : : setPropertyDer ( ui8 what , ui32 val )
{
switch ( what )
{
case 10 :
slots [ 0 ] . count = val ;
break ;
case 11 :
temppower = val ;
break ;
}
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
{
double hlp = h - > getTotalStrength ( ) / getArmyStrength ( ) ;
if ( ! character ) //compliant creatures will always join
return 0 ;
else if ( allowJoin ) //test for joining
{
int factor ;
if ( hlp > = 7 )
factor = 11 ;
else if ( hlp > = 1 )
2009-08-14 09:01:08 +03:00
factor = ( int ) ( 2 * ( hlp - 1 ) ) ;
2009-04-12 04:48:50 +03:00
else if ( hlp > = 0.5 )
factor = - 1 ;
else if ( hlp > = 0.333 )
factor = - 2 ;
else
factor = - 3 ;
int sympathy = 0 ;
std : : set < ui32 > myKindCres ; //what creatures are the same kind as we
myKindCres . insert ( subID ) ; //we
2010-05-02 21:20:26 +03:00
myKindCres . insert ( VLC - > creh - > creatures [ subID ] - > upgrades . begin ( ) , VLC - > creh - > creatures [ subID ] - > upgrades . end ( ) ) ; //our upgrades
for ( std : : vector < CCreature * > : : iterator i = VLC - > creh - > creatures . begin ( ) ; i ! = VLC - > creh - > creatures . end ( ) ; i + + )
if ( vstd : : contains ( ( * i ) - > upgrades , ( ui32 ) id ) ) //it's our base creatures
myKindCres . insert ( ( * i ) - > idNumber ) ;
2009-04-12 04:48:50 +03:00
int count = 0 , //how many creatures of our kind has hero
totalCount = 0 ;
2010-04-02 05:07:40 +03:00
2010-05-02 21:20:26 +03:00
for ( TSlots : : const_iterator i = h - > Slots ( ) . begin ( ) ; i ! = h - > Slots ( ) . end ( ) ; i + + )
2009-04-12 04:48:50 +03:00
{
2010-04-02 05:07:40 +03:00
if ( vstd : : contains ( myKindCres , i - > second . type - > idNumber ) )
count + = i - > second . count ;
totalCount + = i - > second . count ;
2009-04-12 04:48:50 +03:00
}
if ( count * 2 > totalCount )
sympathy + + ;
if ( count )
sympathy + + ;
int charisma = factor + h - > getSecSkillLevel ( 4 ) + sympathy ;
if ( charisma > = character ) //creatures might join...
{
if ( h - > getSecSkillLevel ( 4 ) + sympathy + 1 > = character )
return 0 ; //join for free
else if ( h - > getSecSkillLevel ( 4 ) * 2 + sympathy + 1 > = character )
2010-05-02 21:20:26 +03:00
return VLC - > creh - > creatures [ subID ] - > cost [ 6 ] * Slots ( ) . find ( 0 ) - > second . count ; //join for gold
2009-04-12 04:48:50 +03:00
}
}
//we are still here - creatures not joined heroes, test for fleeing
//TODO: it's provisional formula, should be replaced with original one (or something closer to it)
//TODO: should be deterministic (will be needed for Vision spell)
2009-04-16 03:28:54 +03:00
int hlp2 = ( int ) ( hlp - 2 ) * 1000 ;
2009-04-12 04:48:50 +03:00
if ( ! neverFlees
& & hlp2 > = 0
& & rand ( ) % 2000 < hlp2
)
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
{
if ( pursue )
{
fight ( h ) ;
}
else
{
cb - > removeObject ( id ) ;
}
}
void CGCreature : : joinDecision ( const CGHeroInstance * h , int cost , ui32 accept ) const
{
if ( ! accept )
{
if ( takenAction ( h , false ) = = - 1 ) //they flee
{
flee ( h ) ;
}
else //they fight
{
InfoWindow iw ;
iw . player = h - > tempOwner ;
iw . text < < std : : pair < ui8 , ui32 > ( 11 , 87 ) ; //Insulted by your refusal of their offer, the monsters attack!
cb - > showInfoDialog ( & iw ) ;
fight ( h ) ;
}
}
else //accepted
{
if ( cb - > getResource ( h - > tempOwner , 6 ) < cost ) //player don't have enough gold!
{
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 )
cb - > giveResource ( h - > tempOwner , 6 , - cost ) ;
2010-05-02 21:20:26 +03:00
int slot = h - > getSlotFor ( subID ) ;
2009-04-12 04:48:50 +03:00
if ( slot > = 0 ) //there is place
{
//add creatures
SetGarrisons sg ;
2010-05-02 21:20:26 +03:00
sg . garrs [ h - > id ] = h - > getArmy ( ) ;
sg . garrs [ h - > id ] . addToSlot ( slot , subID , getAmount ( 0 ) ) ;
2009-04-12 04:48:50 +03:00
cb - > sendAndApply ( & sg ) ;
cb - > removeObject ( id ) ;
}
else
{
2009-09-09 20:49:03 +03:00
cb - > showGarrisonDialog ( id , h - > id , true , boost : : bind ( & IGameCallback : : removeObject , cb , id ) ) ; //show garrison window and remove ourselves from map when player ends
2009-04-12 04:48:50 +03:00
}
}
}
void CGCreature : : fight ( const CGHeroInstance * h ) const
{
2009-09-13 01:17:23 +03:00
cb - > startBattleI ( h , this , boost : : bind ( & CGCreature : : endBattle , this , _1 ) ) ;
2009-04-12 04:48:50 +03:00
}
void CGCreature : : flee ( const CGHeroInstance * h ) const
{
BlockingDialog ynd ( true , false ) ;
ynd . player = h - > tempOwner ;
ynd . text < < std : : pair < ui8 , ui32 > ( 11 , 91 ) ;
2009-07-09 22:15:22 +03:00
ynd . text . addReplacement ( MetaString : : CRE_PL_NAMES , subID ) ;
2009-04-12 04:48:50 +03:00
cb - > showBlockingDialog ( & ynd , boost : : bind ( & CGCreature : : fleeDecision , this , h , _1 ) ) ;
}
2008-12-27 03:01:59 +02:00
void CGMine : : onHeroVisit ( const CGHeroInstance * h ) const
{
if ( h - > tempOwner = = tempOwner ) //we're visiting our mine
2009-04-12 03:58:41 +03:00
{
2009-09-09 20:49:03 +03:00
cb - > showGarrisonDialog ( id , h - > id , true , 0 ) ;
2009-04-12 03:58:41 +03:00
return ;
}
2008-12-27 03:01:59 +02:00
2010-07-31 03:26:34 +03:00
if ( subID > = 7 ) //Abandoned mine
{
BlockingDialog ynd ( true , false ) ;
ynd . player = h - > tempOwner ;
ynd . text < < std : : pair < ui8 , ui32 > ( MetaString : : ADVOB_TXT , 84 ) ;
cb - > showBlockingDialog ( & ynd , boost : : bind ( & CGMine : : fight , this , _1 , h ) ) ;
return ;
}
2008-12-27 03:01:59 +02:00
2010-07-31 03:26:34 +03:00
//TODO: check if mine is guarded
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 ;
2008-12-27 03:01:59 +02:00
if ( tempOwner = = NEUTRAL_PLAYER )
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 ;
CStackInstance troglodytes ( 70 , howManyTroglodytes ) ;
addStack ( 0 , troglodytes ) ;
//after map reading tempOwner placeholds bitmask for allowed resources
std : : vector < int > possibleResources ;
for ( int i = 0 ; i < 8 ; i + + )
if ( tempOwner & 1 < < i )
possibleResources . push_back ( i ) ;
assert ( possibleResources . size ( ) ) ;
producedResource = possibleResources [ ran ( ) % possibleResources . size ( ) ] ;
tempOwner = NEUTRAL_PLAYER ;
hoverName = VLC - > generaltexth - > mines [ 7 ] . first + " \n " + VLC - > generaltexth - > allTexts [ 202 ] + " " + troglodytes . getQuantityTXT ( false ) + " " + troglodytes . type - > namePl ;
}
2008-12-27 03:01:59 +02:00
else
2010-07-31 03:26:34 +03:00
{
producedResource = subID ;
MetaString ms ;
ms < < std : : pair < ui8 , ui32 > ( 9 , producedResource ) ;
if ( tempOwner > = PLAYER_LIMIT )
tempOwner = NEUTRAL_PLAYER ;
else
ms < < " ( " < < std : : pair < ui8 , ui32 > ( 6 , 23 + tempOwner ) < < " ) " ;
ms . toString ( hoverName ) ;
}
producedQuantity = defaultResProduction ( ) ;
}
void CGMine : : fight ( ui32 agreed , const CGHeroInstance * h ) const
{
cb - > startBattleI ( h , this , boost : : bind ( & CGMine : : endBattle , this , _1 , h - > tempOwner ) ) ;
}
void CGMine : : endBattle ( BattleResult * result , ui8 attackingPlayer ) const
{
if ( result - > winner = = 0 ) //attacker won
{
if ( subID = = 7 )
{
InfoWindow iw ;
iw . player = attackingPlayer ;
iw . text . addTxt ( MetaString : : ADVOB_TXT , 85 ) ;
cb - > showInfoDialog ( & iw ) ;
}
flagMine ( attackingPlayer ) ;
}
}
void CGMine : : flagMine ( ui8 player ) const
{
assert ( tempOwner ! = player ) ;
cb - > setOwner ( id , player ) ; //not ours? flag it!
MetaString ms ;
ms < < std : : pair < ui8 , ui32 > ( 9 , subID ) < < " \n ( " < < std : : pair < ui8 , ui32 > ( 6 , 23 + player ) < < " ) " ;
if ( subID = = 7 )
{
ms < < " (%s) " ;
ms . addReplacement ( MetaString : : RES_NAMES , producedResource ) ;
}
cb - > setHoverName ( id , & ms ) ;
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 ;
iw . components . push_back ( Component ( 2 , producedResource , producedQuantity , - 1 ) ) ;
cb - > showInfoDialog ( & iw ) ;
}
ui32 CGMine : : defaultResProduction ( )
{
switch ( producedResource )
{
case 0 : //wood
case 2 : //ore
return 2 ;
case 6 : //gold
return 1000 ;
default :
return 1 ;
}
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 :
amount = 500 + ( rand ( ) % 6 ) * 100 ;
break ;
case 0 : case 2 :
amount = 6 + ( rand ( ) % 5 ) ;
break ;
default :
amount = 3 + ( rand ( ) % 3 ) ;
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 ;
2009-04-11 04:32:50 +03:00
cb - > showBlockingDialog ( & ynd , boost : : bind ( & CGResource : : fightForRes , this , _1 , h ) ) ;
2009-01-11 00:08:18 +02:00
}
else
{
2009-05-02 01:08:03 +03:00
fightForRes ( 1 , h ) ;
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
2009-01-11 00:08:18 +02:00
void CGResource : : collectRes ( int player ) const
{
cb - > giveResource ( player , subID , amount ) ;
2008-12-27 03:01:59 +02:00
ShowInInfobox sii ;
2009-01-11 00:08:18 +02:00
sii . player = player ;
2008-12-27 03:01:59 +02:00
sii . c = Component ( 2 , subID , amount , 0 ) ;
sii . text < < std : : pair < ui8 , ui32 > ( 11 , 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 ) ;
cb - > removeObject ( id ) ;
}
2009-04-11 04:32:50 +03:00
void CGResource : : fightForRes ( ui32 agreed , const CGHeroInstance * h ) const
2009-01-11 00:08:18 +02:00
{
2009-04-11 04:32:50 +03:00
if ( agreed )
2009-09-13 01:17:23 +03:00
cb - > startBattleI ( h , this , boost : : bind ( & CGResource : : endBattle , this , _1 , h ) ) ;
2009-01-11 00:08:18 +02:00
}
void CGResource : : endBattle ( BattleResult * result , const CGHeroInstance * h ) const
{
if ( result - > winner = = 0 ) //attacker won
collectRes ( h - > getOwner ( ) ) ;
}
2008-12-27 03:01:59 +02:00
void CGVisitableOPW : : newTurn ( ) const
{
if ( cb - > getDate ( 1 ) = = 1 ) //first day of week
{
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 ) ;
cb - > setHoverName ( id , & ms ) ;
}
}
void CGVisitableOPW : : onHeroVisit ( const CGHeroInstance * h ) const
{
2009-09-23 15:05:33 +03:00
int mid , sound = 0 ;
2008-12-27 03:01:59 +02:00
switch ( ID )
{
2009-04-24 00:09:10 +03:00
case 55 : //mystical garden
sound = soundBase : : experience ;
2008-12-27 03:01:59 +02:00
mid = 92 ;
break ;
2009-04-24 00:09:10 +03:00
case 112 : //windmill
sound = soundBase : : GENIE ;
2008-12-27 03:01:59 +02:00
mid = 170 ;
break ;
2009-04-24 00:09:10 +03:00
case 109 : //waterwheel
sound = soundBase : : GENIE ;
2008-12-27 03:01:59 +02:00
mid = 164 ;
break ;
}
if ( visited )
{
if ( ID ! = 112 )
mid + + ;
else
mid - - ;
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 . text < < std : : pair < ui8 , ui32 > ( 11 , mid ) ;
cb - > showInfoDialog ( & iw ) ;
}
else
{
int type , sub , val ;
type = 2 ;
switch ( ID )
{
case 55 :
if ( rand ( ) % 2 )
{
sub = 5 ;
val = 5 ;
}
else
{
sub = 6 ;
val = 500 ;
}
break ;
case 112 :
mid = 170 ;
sub = ( rand ( ) % 5 ) + 1 ;
val = ( rand ( ) % 4 ) + 3 ;
break ;
case 109 :
mid = 164 ;
sub = 6 ;
2009-02-15 21:49:23 +02:00
if ( cb - > getDate ( 0 ) < 8 )
2008-12-27 03:01:59 +02:00
val = 500 ;
else
val = 1000 ;
}
cb - > giveResource ( h - > tempOwner , sub , val ) ;
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 ) ) ;
iw . text < < std : : pair < ui8 , ui32 > ( 11 , mid ) ;
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"
ms < < std : : pair < ui8 , ui32 > ( 3 , ID ) < < " " < < std : : pair < ui8 , ui32 > ( 1 , 352 ) ;
cb - > setHoverName ( id , & ms ) ;
}
}
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
{
int destinationid = - 1 ;
switch ( ID )
{
2009-07-14 19:20:15 +03:00
case 43 : //one way - find corresponding exit monolith
2008-12-27 03:01:59 +02:00
if ( vstd : : contains ( objs , 44 ) & & vstd : : contains ( objs [ 44 ] , subID ) & & objs [ 44 ] [ subID ] . size ( ) )
destinationid = objs [ 44 ] [ subID ] [ rand ( ) % objs [ 44 ] [ subID ] . size ( ) ] ;
else
tlog2 < < " Cannot find corresponding exit monolith for " < < id < < std : : endl ;
break ;
2010-06-07 16:11:08 +03:00
case 45 : //two way monolith - pick any other one
case 111 : //Whirlpool
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
if ( ID = = 111 )
{
if ( ! h - > hasBonusOfType ( Bonus : : WHIRLPOOL_PROTECTION ) )
{
CCreatureSet army = h - > getArmy ( ) ;
2010-06-25 11:19:39 +03:00
if ( army . Slots ( ) . size ( ) > 1 | | army . Slots ( ) . begin ( ) - > second . count > 1 )
{ //we can't remove last unit
int targetstack = army . Slots ( ) . begin ( ) - > first ; //slot numbers may vary
for ( TSlots : : const_reverse_iterator i = army . Slots ( ) . rbegin ( ) ; i ! = army . Slots ( ) . rend ( ) ; i + + )
2010-06-07 16:11:08 +03:00
{
2010-06-25 11:19:39 +03:00
if ( army . getPower ( targetstack ) > army . getPower ( i - > first ) )
{
targetstack = ( i - > first ) ;
}
2010-06-07 16:11:08 +03:00
}
2010-06-25 11:19:39 +03:00
CCreatureSet ourArmy ;
ourArmy . addStack ( targetstack , army . getStack ( targetstack ) ) ;
TQuantity tq = ( double ) ( ourArmy . getAmount ( targetstack ) ) * 0.5 ;
amax ( tq , 1 ) ;
2010-06-07 16:11:08 +03:00
ourArmy . setStackCount ( targetstack , tq ) ;
InfoWindow iw ;
iw . player = h - > tempOwner ;
iw . text . addTxt ( MetaString : : ADVOB_TXT , 168 ) ;
iw . components . push_back ( Component ( ourArmy . getStack ( targetstack ) ) ) ;
cb - > showInfoDialog ( & iw ) ;
cb - > takeCreatures ( h - > id , ourArmy . Slots ( ) ) ;
}
}
}
}
2008-12-27 03:01:59 +02:00
else
tlog2 < < " Cannot find corresponding exit monolith for " < < id < < std : : endl ;
break ;
case 103 : //find nearest subterranean gate on the other level
{
2010-02-10 05:35:48 +02:00
int i = 0 ;
for ( ; i < gates . size ( ) ; i + + )
2008-12-27 03:01:59 +02:00
{
2009-09-07 05:29:44 +03:00
if ( gates [ i ] . first = = id )
{
destinationid = gates [ i ] . second ;
break ;
}
else if ( gates [ i ] . second = = id )
2008-12-27 03:01:59 +02:00
{
2009-09-07 05:29:44 +03:00
destinationid = gates [ i ] . first ;
break ;
2008-12-27 03:01:59 +02:00
}
}
2010-02-10 05:35:48 +02:00
if ( destinationid < 0 | | i = = gates . size ( ) ) //no exit
{
InfoWindow iw ;
iw . player = h - > tempOwner ;
2010-06-07 16:11:08 +03:00
iw . text . addTxt ( MetaString : : ADVOB_TXT , 153 ) ; //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
cb - > sendAndApply ( & iw ) ;
}
2008-12-27 03:01:59 +02:00
break ;
}
}
if ( destinationid < 0 )
{
2009-09-07 05:29:44 +03:00
tlog2 < < " Cannot find exit... (obj at " < < pos < < " ) :( \n " ;
2008-12-27 03:01:59 +02:00
return ;
}
2010-06-25 11:19:39 +03:00
if ( ID = = 111 )
cb - > moveHero ( h - > id , CGHeroInstance : : convertPosition ( cb - > getObj ( destinationid ) - > pos , true ) + ( h - > pos - pos ) - int3 ( 1 , 0 , 0 ) , true ) ;
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 )
{
case 103 : //ignore subterranean gates subid
case 111 :
{
si = 0 ;
break ;
}
default :
break ;
}
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
for ( size_t i = 0 ; i < objs [ 103 ] [ 0 ] . size ( ) ; i + + )
{
const CGObjectInstance * hlp = cb - > getObj ( objs [ 103 ] [ 0 ] [ i ] ) ;
gatesSplit [ hlp - > pos . z ] . push_back ( hlp ) ;
}
//sort by position
std : : sort ( gatesSplit [ 0 ] . begin ( ) , gatesSplit [ 0 ] . end ( ) , boost : : bind ( & CGObjectInstance : : pos , _1 ) < boost : : bind ( & CGObjectInstance : : pos , _2 ) ) ;
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
{
gates . push_back ( std : : pair < int , int > ( cur - > id , gatesSplit [ 1 ] [ best . first ] - > id ) ) ;
gatesSplit [ 1 ] [ best . first ] = NULL ;
}
else
{
gates . push_back ( std : : pair < int , int > ( cur - > id , - 1 ) ) ;
}
2009-09-07 05:29:44 +03:00
}
objs . erase ( 103 ) ;
2008-12-27 03:01:59 +02:00
}
void CGArtifact : : initObj ( )
{
blockVisit = true ;
if ( ID = = 5 )
2010-06-26 19:02:10 +03:00
hoverName = VLC - > arth - > artifacts [ subID ] - > Name ( ) ;
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
{
2009-03-19 16:17:19 +02:00
if ( ID = = 5 )
{
InfoWindow iw ;
2009-07-21 02:34:06 +03:00
iw . soundID = soundBase : : treasure ;
2009-03-19 16:17:19 +02:00
iw . player = h - > tempOwner ;
iw . components . push_back ( Component ( 4 , subID , 0 , 0 ) ) ;
if ( message . length ( ) )
iw . text < < message ;
else
iw . text < < std : : pair < ui8 , ui32 > ( 12 , subID ) ;
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 ;
2009-04-11 04:32:50 +03:00
cb - > showBlockingDialog ( & ynd , boost : : bind ( & CGArtifact : : fightForArt , this , _1 , h ) ) ;
2009-02-03 07:28:05 +02:00
}
else
{
fightForArt ( 0 , h ) ;
}
}
}
void CGArtifact : : pick ( const CGHeroInstance * h ) const
2008-12-27 03:01:59 +02:00
{
2009-03-19 16:17:19 +02:00
if ( ID = = 5 ) //Artifact
{
cb - > giveHeroArtifact ( subID , h - > id , - 2 ) ;
}
else if ( ID = = 93 ) // Spell scroll
{
//TODO: support for the spell scroll
}
2009-02-01 16:11:41 +02:00
cb - > removeObject ( id ) ;
2008-12-27 03:01:59 +02:00
}
2009-04-11 04:32:50 +03:00
void CGArtifact : : fightForArt ( ui32 agreed , const CGHeroInstance * h ) const
2009-02-03 07:28:05 +02:00
{
2009-04-11 04:32:50 +03:00
if ( agreed )
2009-09-13 01:17:23 +03:00
cb - > startBattleI ( h , this , boost : : bind ( & CGArtifact : : endBattle , this , _1 , h ) ) ;
2009-02-03 07:28:05 +02:00
}
void CGArtifact : : endBattle ( BattleResult * result , const CGHeroInstance * h ) const
{
if ( result - > winner = = 0 ) //attacker won
pick ( h ) ;
}
2008-12-27 03:01:59 +02:00
void CGPickable : : initObj ( )
{
blockVisit = true ;
switch ( ID )
{
case 12 : //campfire
val2 = ( ran ( ) % 3 ) + 4 ; //4 - 6
val1 = val2 * 100 ;
type = ran ( ) % 6 ; //given resource
break ;
2009-07-19 06:10:24 +03:00
case 29 : //floatsam
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 ;
case 82 : //sea chest
{
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 ;
case 86 : //Shipwreck Survivor
{
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 ;
2008-12-27 03:01:59 +02:00
case 101 : //treasure chest
{
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 )
{
case 12 : //campfire
{
cb - > giveResource ( h - > tempOwner , type , val2 ) ; //non-gold resource
cb - > giveResource ( h - > tempOwner , 6 , val1 ) ; //gold
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 ;
iw . components . push_back ( Component ( 2 , 6 , val1 , 0 ) ) ;
iw . components . push_back ( Component ( 2 , type , val2 , 0 ) ) ;
iw . text < < std : : pair < ui8 , ui32 > ( 11 , 23 ) ;
cb - > showInfoDialog ( & iw ) ;
break ;
}
2009-07-19 06:10:24 +03:00
case 29 : //flotsam
{
cb - > giveResource ( h - > tempOwner , 0 , val1 ) ; //wood
cb - > giveResource ( h - > tempOwner , 6 , val2 ) ; //gold
InfoWindow iw ;
iw . soundID = soundBase : : GENIE ;
iw . player = h - > tempOwner ;
if ( val1 )
iw . components . push_back ( Component ( 2 , 0 , val1 , 0 ) ) ;
if ( val2 )
iw . components . push_back ( Component ( 2 , 6 , val2 , 0 ) ) ;
iw . text . addTxt ( MetaString : : ADVOB_TXT , 51 + type ) ;
cb - > showInfoDialog ( & iw ) ;
break ;
}
case 82 : //Sea Chest
{
InfoWindow iw ;
iw . soundID = soundBase : : chest ;
iw . player = h - > tempOwner ;
iw . text . addTxt ( MetaString : : ADVOB_TXT , 116 + type ) ;
if ( val1 ) //there is gold
{
iw . components . push_back ( Component ( 2 , 6 , val1 , 0 ) ) ;
cb - > giveResource ( h - > tempOwner , 6 , val1 ) ;
}
if ( type = = 1 ) //art
{
//TODO: what if no space in backpack?
iw . components . push_back ( Component ( 4 , val2 , 1 , 0 ) ) ;
iw . text . addReplacement ( MetaString : : ART_NAMES , val2 ) ;
cb - > giveHeroArtifact ( val2 , h - > id , - 2 ) ;
}
cb - > showInfoDialog ( & iw ) ;
break ;
}
case 86 : //Shipwreck Survivor
{
//TODO: what if no space in backpack?
InfoWindow iw ;
iw . soundID = soundBase : : experience ;
iw . player = h - > tempOwner ;
iw . components . push_back ( Component ( 4 , val1 , 1 , 0 ) ) ;
iw . text . addTxt ( MetaString : : ADVOB_TXT , 125 ) ;
iw . text . addReplacement ( MetaString : : ART_NAMES , val1 ) ;
cb - > giveHeroArtifact ( val1 , h - > id , - 2 ) ;
cb - > showInfoDialog ( & iw ) ;
break ;
}
2008-12-27 03:01:59 +02:00
case 101 : //treasure chest
{
if ( subID ) //not OH3 treasure chest
{
tlog2 < < " Not supported WoG treasure chest! \n " ;
return ;
}
if ( type ) //there is an artifact
{
cb - > giveHeroArtifact ( val1 , h - > id , - 2 ) ;
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 ;
iw . components . push_back ( Component ( 4 , val1 , 1 , 0 ) ) ;
iw . text < < std : : pair < ui8 , ui32 > ( 11 , 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 ;
sd . text < < std : : pair < ui8 , ui32 > ( 11 , 146 ) ;
sd . components . push_back ( Component ( 2 , 6 , val1 , 0 ) ) ;
2010-07-26 01:47:59 +03:00
int expVal = val2 * ( 100 + h - > getSecSkillLevel ( 21 ) * 5 ) / 100.0f ;
sd . components . push_back ( Component ( 5 , 0 , expVal , 0 ) ) ;
2009-04-22 21:48:56 +03:00
sd . soundID = soundBase : : chest ;
2008-12-27 03:01:59 +02:00
boost : : function < void ( ui32 ) > fun = boost : : bind ( & CGPickable : : chosen , this , _1 , h - > id ) ;
2009-04-11 04:32:50 +03:00
cb - > showBlockingDialog ( & sd , fun ) ;
2008-12-27 03:01:59 +02:00
return ;
}
}
}
cb - > removeObject ( id ) ;
}
void CGPickable : : chosen ( int which , int heroID ) const
{
2010-07-26 01:47:59 +03:00
const CGHeroInstance * h = cb - > getHero ( heroID ) ;
2008-12-27 03:01:59 +02:00
switch ( which )
{
2009-04-11 04:32:50 +03:00
case 1 : //player pick gold
2008-12-27 03:01:59 +02:00
cb - > giveResource ( cb - > getOwner ( heroID ) , 6 , val1 ) ;
break ;
2009-04-11 04:32:50 +03:00
case 2 : //player pick exp
2010-07-26 01:47:59 +03:00
cb - > changePrimSkill ( heroID , 4 , val2 * ( 100 + h - > getSecSkillLevel ( 21 ) * 5 ) / 100.0f ) ;
2008-12-27 03:01:59 +02:00
break ;
default :
throw std : : string ( " Unhandled treasure choice " ) ;
}
2009-01-11 00:08:18 +02:00
cb - > removeObject ( id ) ;
}
2009-12-31 13:43:37 +02:00
bool CQuest : : checkQuest ( const CGHeroInstance * h ) const
{
switch ( missionType )
{
case MISSION_NONE :
return true ;
break ;
case MISSION_LEVEL :
if ( m13489val < = h - > level )
return true ;
return false ;
break ;
case MISSION_PRIMARY_STAT :
for ( int i = 0 ; i < 4 ; + + i )
{
2010-05-02 21:20:26 +03:00
if ( h - > getPrimSkillLevel ( i ) < m2stats [ i ] )
2009-12-31 13:43:37 +02:00
return false ;
}
return true ;
break ;
case MISSION_KILL_HERO :
2010-02-04 22:34:20 +02:00
if ( h - > cb - > gameState ( ) - > map - > heroesToBeat [ m13489val ] - > tempOwner < PLAYER_LIMIT )
2010-01-01 14:15:20 +02:00
return false ; //if the pointer is not NULL
return true ;
break ;
2009-12-31 13:43:37 +02:00
case MISSION_KILL_CREATURE :
2010-02-07 18:05:27 +02:00
if ( h - > cb - > gameState ( ) - > map - > monsters [ m13489val ] - > pos = = int3 ( - 1 , - 1 , - 1 ) )
return true ;
return false ;
2009-12-31 13:43:37 +02:00
break ;
case MISSION_ART :
for ( int i = 0 ; i < m5arts . size ( ) ; + + i )
{
2010-02-04 22:34:20 +02:00
if ( h - > hasArt ( m5arts [ i ] ) )
2009-12-31 13:43:37 +02:00
continue ;
return false ; //if the artifact was not found
}
return true ;
break ;
case MISSION_ARMY :
2010-01-01 14:15:20 +02:00
{
TSlots : : const_iterator it , cre ;
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-04-02 05:07:40 +03:00
if ( it - > second . type = = cre - > second . type )
count + = it - > second . count ;
2010-01-01 14:15:20 +02:00
}
2010-04-02 05:07:40 +03:00
if ( count < cre - > second . count ) //not enough creatures of this kind
2010-01-01 14:15:20 +02:00
return false ;
}
}
return true ;
break ;
2009-12-31 13:43:37 +02:00
case MISSION_RESOURCES :
for ( int i = 0 ; i < 7 ; + + i ) //including Mithril ?
{ //Quest has no direct access to callback
if ( h - > cb - > getResource ( h - > tempOwner , i ) < m7resources [ i ] )
return false ;
}
return true ;
break ;
case MISSION_HERO :
2010-02-04 22:34:20 +02:00
if ( m13489val = = h - > type - > ID )
2009-12-31 13:43:37 +02:00
return true ;
return false ;
break ;
case MISSION_PLAYER :
if ( m13489val = = h - > getOwner ( ) )
return true ;
return false ;
break ;
default :
return false ;
}
}
2010-01-01 14:15:20 +02:00
void CGSeerHut : : initObj ( )
{
2010-01-27 07:11:31 +02:00
seerName = VLC - > generaltexth - > seerNames [ ran ( ) % VLC - > generaltexth - > seerNames . size ( ) ] ;
2010-01-30 22:53:47 +02:00
textOption = ran ( ) % 3 ;
progress = 0 ;
2010-06-06 12:50:37 +03:00
if ( missionType )
2010-02-02 19:05:03 +02:00
{
2010-06-06 12:50:37 +03:00
if ( ! isCustom )
{
firstVisitText = VLC - > generaltexth - > quests [ missionType - 1 ] [ 0 ] [ textOption ] ;
nextVisitText = VLC - > generaltexth - > quests [ missionType - 1 ] [ 1 ] [ textOption ] ;
completedText = VLC - > generaltexth - > quests [ missionType - 1 ] [ 2 ] [ textOption ] ;
}
2010-02-02 19:05:03 +02:00
}
else
firstVisitText = VLC - > generaltexth - > seerEmpty [ textOption ] ;
2010-06-06 12:50:37 +03:00
2010-01-01 14:15:20 +02:00
}
2009-12-30 22:49:10 +02:00
const std : : string & CGSeerHut : : getHoverText ( ) const
{
2010-02-07 18:05:27 +02:00
switch ( ID )
{
case 83 :
hoverName = VLC - > generaltexth - > allTexts [ 347 ] ;
boost : : algorithm : : replace_first ( hoverName , " %s " , seerName ) ;
break ;
case 215 :
hoverName = VLC - > generaltexth - > names [ ID ] ;
break ;
default :
tlog5 < < " unrecognized quest object \n " ;
}
if ( progress & missionType ) //rollover when the quest is active
{
MetaString ms ;
ms < < " \n \n " < < VLC - > generaltexth - > quests [ missionType - 1 ] [ 3 ] [ textOption ] ;
std : : string str ;
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 ] ) ;
}
}
ms . addReplacement ( loot . buildList ( ) ) ;
}
break ;
case MISSION_KILL_HERO :
ms . addReplacement ( cb - > gameState ( ) - > map - > heroesToBeat [ m13489val ] - > name ) ;
break ;
case MISSION_HERO :
ms . addReplacement ( VLC - > heroh - > heroes [ m13489val ] - > name ) ;
break ;
case MISSION_KILL_CREATURE :
2010-04-02 05:07:40 +03:00
{
2010-05-02 21:20:26 +03:00
ms . addReplacement ( cb - > gameState ( ) - > map - > monsters [ m13489val ] - > getStack ( 0 ) ) ;
2010-04-02 05:07:40 +03:00
}
2010-02-07 18:05:27 +02:00
break ;
case MISSION_ART :
{
2010-04-02 05:07:40 +03:00
MetaString loot ;
for ( std : : vector < ui16 > : : const_iterator it = m5arts . begin ( ) ; it ! = m5arts . end ( ) ; + + it )
{
loot < < " %s " ;
loot . addReplacement ( MetaString : : ART_NAMES , * it ) ;
}
ms . addReplacement ( loot . buildList ( ) ) ;
2010-02-07 18:05:27 +02:00
}
break ;
case MISSION_ARMY :
2010-05-03 09:25:19 +03:00
{
MetaString loot ;
for ( TSlots : : const_iterator it = m6creatures . begin ( ) ; it ! = m6creatures . end ( ) ; + + it )
{
loot < < " %s " ;
loot . addReplacement ( it - > second ) ;
}
ms . addReplacement ( loot . buildList ( ) ) ;
}
break ;
2010-02-07 18:05:27 +02:00
case MISSION_RESOURCES :
2010-05-03 09:25:19 +03:00
{
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 ;
2010-02-07 18:05:27 +02:00
case MISSION_PLAYER :
ms . addReplacement ( VLC - > generaltexth - > colors [ m13489val ] ) ;
break ;
default :
break ;
}
ms . toString ( str ) ;
hoverName + = str ;
}
2010-01-30 22:53:47 +02:00
return hoverName ;
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 :
progress = val ;
break ;
case 11 :
missionType = CQuest : : MISSION_NONE ;
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
{
if ( lastDay > = 0 & & lastDay < = cb - > getDate ( 0 ) ) //time is up
{
cb - > setObjProperty ( id , 11 , 0 ) ;
cb - > setObjProperty ( id , 10 , 0 ) ;
}
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 ( ) ;
if ( missionType )
2010-01-01 14:15:20 +02:00
{
2010-02-02 19:05:03 +02:00
if ( ! progress ) //propose quest
2010-01-01 14:15:20 +02:00
{
2010-02-02 19:05:03 +02:00
iw . text < < firstVisitText ;
switch ( missionType )
{
case MISSION_LEVEL :
iw . components . push_back ( Component ( Component : : EXPERIENCE , 1 , m13489val , 0 ) ) ;
2010-05-03 09:25:19 +03:00
if ( ! isCustom )
iw . text . addReplacement ( m13489val ) ;
2010-02-02 19:05:03 +02:00
break ;
case MISSION_PRIMARY_STAT :
{
MetaString loot ;
for ( int i = 0 ; i < 4 ; + + i )
{
if ( m2stats [ i ] )
{
iw . components . push_back ( Component ( Component : : PRIM_SKILL , i , m2stats [ i ] , 0 ) ) ;
loot < < " %d %s " ;
loot . addReplacement ( m2stats [ i ] ) ;
loot . addReplacement ( VLC - > generaltexth - > primarySkillNames [ i ] ) ;
}
}
2010-05-03 09:25:19 +03:00
if ( ! isCustom )
iw . text . addReplacement ( loot . buildList ( ) ) ;
2010-02-02 19:05:03 +02:00
}
break ;
case MISSION_KILL_HERO :
2010-02-04 22:34:20 +02:00
iw . components . push_back ( Component ( Component : : HERO ,
cb - > gameState ( ) - > map - > heroesToBeat [ m13489val ] - > type - > ID , 0 , 0 ) ) ;
2010-05-03 09:25:19 +03:00
if ( ! isCustom )
iw . text . addReplacement ( cb - > gameState ( ) - > map - > heroesToBeat [ m13489val ] - > name ) ;
2010-02-04 22:34:20 +02:00
break ;
2010-02-02 19:05:03 +02:00
case MISSION_HERO :
2010-02-04 22:34:20 +02:00
iw . components . push_back ( Component ( Component : : HERO , m13489val , 0 , 0 ) ) ;
2010-05-03 09:25:19 +03:00
if ( ! isCustom )
iw . text . addReplacement ( VLC - > heroh - > heroes [ m13489val ] - > name ) ;
2010-02-02 19:05:03 +02:00
break ;
case MISSION_KILL_CREATURE :
2010-02-04 22:34:20 +02:00
{
2010-05-02 21:20:26 +03:00
CStackInstance stack = cb - > gameState ( ) - > map - > monsters [ m13489val ] - > getStack ( 0 ) ;
2010-04-02 05:07:40 +03:00
iw . components . push_back ( Component ( stack ) ) ;
2010-05-03 09:25:19 +03:00
if ( ! isCustom )
2010-04-02 05:07:40 +03:00
{
2010-05-03 09:25:19 +03:00
iw . text . addReplacement ( stack ) ;
if ( std : : count ( firstVisitText . begin ( ) , firstVisitText . end ( ) , ' % ' ) = = 2 ) //say where is placed monster
{
iw . text . addReplacement ( VLC - > generaltexth - > arraytxt [ 147 + checkDirection ( ) ] ) ;
}
2010-04-02 05:07:40 +03:00
}
2010-02-04 22:34:20 +02:00
}
2010-02-02 19:05:03 +02:00
break ;
case MISSION_ART :
{
MetaString loot ;
for ( std : : vector < ui16 > : : const_iterator it = m5arts . begin ( ) ; it ! = m5arts . end ( ) ; + + it )
{
iw . components . push_back ( Component ( Component : : ARTIFACT , * it , 0 , 0 ) ) ;
loot < < " %s " ;
loot . addReplacement ( MetaString : : ART_NAMES , * it ) ;
}
2010-05-03 09:25:19 +03:00
if ( ! isCustom )
iw . text . addReplacement ( loot . buildList ( ) ) ;
2010-02-02 19:05:03 +02:00
}
break ;
case MISSION_ARMY :
{
MetaString loot ;
for ( TSlots : : const_iterator it = m6creatures . begin ( ) ; it ! = m6creatures . end ( ) ; + + it )
{
2010-04-02 05:07:40 +03:00
iw . components . push_back ( Component ( it - > second ) ) ;
2010-02-02 19:05:03 +02:00
loot < < " %s " ;
2010-04-02 05:07:40 +03:00
loot . addReplacement ( it - > second ) ;
2010-02-02 19:05:03 +02:00
}
2010-05-03 09:25:19 +03:00
if ( ! isCustom )
iw . text . addReplacement ( loot . buildList ( ) ) ;
2010-02-02 19:05:03 +02:00
}
break ;
case MISSION_RESOURCES :
{
MetaString loot ;
for ( int i = 0 ; i < 7 ; + + i )
{
if ( m7resources [ i ] )
{
iw . components . push_back ( Component ( Component : : RESOURCE , i , m7resources [ i ] , 0 ) ) ;
loot < < " %d %s " ;
2010-05-03 09:25:19 +03:00
loot . addReplacement ( m7resources [ i ] ) ;
loot . addReplacement ( MetaString : : RES_NAMES , i ) ;
2010-02-02 19:05:03 +02:00
}
}
2010-05-03 09:25:19 +03:00
if ( ! isCustom )
iw . text . addReplacement ( loot . buildList ( ) ) ;
2010-02-02 19:05:03 +02:00
}
break ;
case MISSION_PLAYER :
iw . components . push_back ( Component ( Component : : FLAG , m13489val , 0 , 0 ) ) ;
2010-05-03 09:25:19 +03:00
if ( ! isCustom )
iw . text . addReplacement ( VLC - > generaltexth - > colors [ m13489val ] ) ;
2010-02-02 19:05:03 +02:00
break ;
}
cb - > setObjProperty ( id , 10 , 1 ) ;
2010-02-07 18:05:27 +02:00
cb - > showInfoDialog ( & iw ) ;
2010-01-01 14:15:20 +02:00
}
2010-02-07 18:05:27 +02:00
else if ( ! checkQuest ( h ) )
2010-02-02 19:05:03 +02:00
{
2010-02-07 18:05:27 +02:00
iw . text < < nextVisitText ;
cb - > showInfoDialog ( & iw ) ;
}
if ( checkQuest ( h ) ) // propose completion, also on first visit
{
BlockingDialog bd ( true , false ) ;
bd . player = h - > getOwner ( ) ;
bd . soundID = soundBase : : QUEST ;
bd . text < < completedText ;
switch ( missionType )
2010-01-30 22:53:47 +02:00
{
2010-02-07 18:05:27 +02:00
case CQuest : : MISSION_LEVEL :
2010-05-03 09:25:19 +03:00
if ( ! isCustom )
bd . text . addReplacement ( m13489val ) ;
2010-02-07 18:05:27 +02:00
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 )
2010-02-02 19:05:03 +02:00
{
2010-02-07 18:05:27 +02:00
if ( m2stats [ i ] )
2010-02-02 19:05:03 +02:00
{
2010-02-07 18:05:27 +02:00
loot < < " %d %s " ;
loot . addReplacement ( m2stats [ i ] ) ;
loot . addReplacement ( VLC - > generaltexth - > primarySkillNames [ i ] ) ;
2010-02-02 19:05:03 +02:00
}
}
2010-05-03 09:25:19 +03:00
if ( ! isCustom )
bd . text . addReplacement ( loot . buildList ( ) ) ;
2010-02-07 18:05:27 +02:00
}
break ;
case CQuest : : MISSION_ART :
{
MetaString loot ;
for ( std : : vector < ui16 > : : const_iterator it = m5arts . begin ( ) ; it ! = m5arts . end ( ) ; + + it )
{
loot < < " %s " ;
loot . addReplacement ( MetaString : : ART_NAMES , * it ) ;
}
2010-05-03 09:25:19 +03:00
if ( ! isCustom )
bd . text . addReplacement ( loot . buildList ( ) ) ;
2010-02-07 18:05:27 +02:00
}
break ;
case CQuest : : MISSION_ARMY :
{
MetaString loot ;
for ( TSlots : : const_iterator it = m6creatures . begin ( ) ; it ! = m6creatures . end ( ) ; + + it )
{
loot < < " %s " ;
2010-04-02 05:07:40 +03:00
loot . addReplacement ( it - > second ) ;
2010-02-07 18:05:27 +02:00
}
2010-05-03 09:25:19 +03:00
if ( ! isCustom )
bd . text . addReplacement ( loot . buildList ( ) ) ;
2010-02-07 18:05:27 +02:00
}
break ;
case CQuest : : MISSION_RESOURCES :
{
MetaString loot ;
for ( int i = 0 ; i < 7 ; + + i )
{
if ( m7resources [ i ] )
2010-02-02 19:05:03 +02:00
{
2010-02-07 18:05:27 +02:00
loot < < " %d %s " ;
2010-05-03 09:25:19 +03:00
loot . addReplacement ( m7resources [ i ] ) ;
loot . addReplacement ( MetaString : : RES_NAMES , i ) ;
2010-02-02 19:05:03 +02:00
}
2010-02-07 18:05:27 +02:00
}
2010-05-03 09:25:19 +03:00
if ( ! isCustom )
bd . text . addReplacement ( loot . buildList ( ) ) ;
2010-02-07 18:05:27 +02:00
}
break ;
case MISSION_KILL_HERO :
2010-05-03 09:25:19 +03:00
if ( ! isCustom )
bd . text . addReplacement ( cb - > gameState ( ) - > map - > heroesToBeat [ m13489val ] - > name ) ;
2010-02-07 18:05:27 +02:00
break ;
case MISSION_HERO :
2010-05-03 09:25:19 +03:00
if ( ! isCustom )
bd . text . addReplacement ( VLC - > heroh - > heroes [ m13489val ] - > name ) ;
2010-02-07 18:05:27 +02:00
break ;
case MISSION_KILL_CREATURE :
{
{
2010-05-03 09:25:19 +03:00
bd . text . addReplacement ( cb - > gameState ( ) - > map - > monsters [ m13489val ] - > getArmy ( ) [ 0 ] ) ;
if ( std : : count ( firstVisitText . begin ( ) , firstVisitText . end ( ) , ' % ' ) = = 2 ) //say where is placed monster
{
bd . text . addReplacement ( VLC - > generaltexth - > arraytxt [ 147 + checkDirection ( ) ] ) ;
}
2010-02-07 18:05:27 +02:00
}
2010-02-02 19:05:03 +02:00
}
2010-02-14 08:53:37 +02:00
case MISSION_PLAYER :
2010-05-03 09:25:19 +03:00
if ( ! isCustom )
bd . text . addReplacement ( VLC - > generaltexth - > colors [ m13489val ] ) ;
2010-02-14 08:53:37 +02:00
break ;
2010-01-30 22:53:47 +02:00
}
2010-07-29 01:39:56 +03:00
switch ( rewardType )
{
case 1 : bd . components . push_back ( Component ( Component : : EXPERIENCE , 0 , rVal * ( 100 + h - > getSecSkillLevel ( 21 ) * 5 ) / 100.0f , 0 ) ) ;
break ;
case 2 : bd . components . push_back ( Component ( Component : : PRIM_SKILL , 5 , rVal , 0 ) ) ;
break ;
case 3 : bd . components . push_back ( Component ( Component : : MORALE , 0 , rVal , 0 ) ) ;
break ;
case 4 : bd . components . push_back ( Component ( Component : : LUCK , 0 , rVal , 0 ) ) ;
break ;
case 5 : bd . components . push_back ( Component ( Component : : RESOURCE , rID , rVal , 0 ) ) ;
break ;
case 6 : bd . components . push_back ( Component ( Component : : PRIM_SKILL , rID , rVal , 0 ) ) ;
break ;
case 7 : bd . components . push_back ( Component ( Component : : SEC_SKILL , rID , rVal , 0 ) ) ;
break ;
case 8 : bd . components . push_back ( Component ( Component : : ARTIFACT , rID , 0 , 0 ) ) ;
break ;
case 9 : bd . components . push_back ( Component ( Component : : SPELL , rID , 0 , 0 ) ) ;
break ;
case 10 : bd . components . push_back ( Component ( Component : : CREATURE , rID , rVal , 0 ) ) ;
break ;
}
2010-02-07 18:05:27 +02:00
cb - > showBlockingDialog ( & bd , boost : : bind ( & CGSeerHut : : finishQuest , this , h , _1 ) ) ;
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
{
iw . text < < VLC - > generaltexth - > seerEmpty [ textOption ] ;
2010-02-04 22:34:20 +02:00
if ( ID = = 83 )
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
{
int3 cord = cb - > gameState ( ) - > map - > monsters [ m13489val ] - > pos ;
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-02-02 19:05:03 +02:00
void CGSeerHut : : finishQuest ( const CGHeroInstance * h , ui32 accept ) const
{
if ( accept )
{
switch ( missionType )
{
case CQuest : : MISSION_ART :
for ( std : : vector < ui16 > : : const_iterator it = m5arts . begin ( ) ; it ! = m5arts . end ( ) ; + + it )
2010-02-07 18:05:27 +02:00
{
cb - > removeArtifact ( * it , h - > id ) ;
}
2010-02-02 19:05:03 +02:00
break ;
case CQuest : : MISSION_ARMY :
2010-02-07 18:05:27 +02:00
cb - > takeCreatures ( h - > id , m6creatures ) ;
2010-02-02 19:05:03 +02:00
break ;
case CQuest : : MISSION_RESOURCES :
for ( int i = 0 ; i < 7 ; + + i )
{
cb - > giveResource ( h - > getOwner ( ) , i , - m7resources [ i ] ) ;
}
break ;
default :
break ;
}
2010-02-07 18:05:27 +02:00
cb - > setObjProperty ( id , 11 , 0 ) ; //no more mission avaliable
completeQuest ( h ) ; //make sure to remove QuestQuard 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 )
{
case 1 : //experience
2010-07-26 01:47:59 +03:00
{
int expVal = rVal * ( 100 + h - > getSecSkillLevel ( 21 ) * 5 ) / 100.0f ;
cb - > changePrimSkill ( h - > id , 4 , expVal , false ) ;
2010-02-04 22:34:20 +02:00
break ;
2010-07-26 01:47:59 +03:00
}
2010-02-04 22:34:20 +02:00
case 2 : //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
}
2010-02-04 22:34:20 +02:00
case 3 : case 4 : //morale /luck
{
2010-05-02 21:20:26 +03:00
Bonus hb ( Bonus : : ONE_WEEK , ( rewardType = = 3 ? Bonus : : MORALE : Bonus : : LUCK ) ,
Bonus : : OBJECT , rVal , h - > id , " " , - 1 ) ;
2010-02-04 22:34:20 +02:00
GiveBonus gb ;
2010-02-10 04:56:00 +02:00
gb . id = h - > id ;
2010-02-04 22:34:20 +02:00
gb . bonus = hb ;
cb - > giveHeroBonus ( & gb ) ;
}
break ;
case 5 : //resources
cb - > giveResource ( h - > getOwner ( ) , rID , rVal ) ;
break ;
case 6 : //main ability bonus (attak, defence etd.)
cb - > changePrimSkill ( h - > id , rID , rVal , false ) ;
break ;
case 7 : // secondary ability gain
cb - > changeSecSkill ( h - > id , rID , rVal , false ) ;
break ;
case 8 : // artifact
cb - > giveHeroArtifact ( rID , h - > id , - 2 ) ;
break ;
case 9 : // spell
{
std : : set < ui32 > spell ;
spell . insert ( rID ) ;
cb - > changeSpells ( h - > id , true , spell ) ;
}
break ;
case 10 : // creature
{
CCreatureSet creatures ;
creatures . setCreature ( 0 , rID , rVal ) ;
cb - > giveCreatures ( id , h , creatures ) ;
}
break ;
default :
break ;
}
2010-01-01 14:15:20 +02:00
}
2010-01-30 22:53:47 +02:00
void CGQuestGuard : : initObj ( )
{
2010-02-04 22:34:20 +02:00
blockVisit = true ;
2010-01-30 22:53:47 +02:00
progress = 0 ;
textOption = ran ( ) % 3 + 3 ; //3-5
2010-05-03 09:25:19 +03:00
if ( missionType & & ! isCustom )
2010-02-02 19:05:03 +02:00
{
firstVisitText = VLC - > generaltexth - > quests [ missionType - 1 ] [ 0 ] [ textOption ] ;
nextVisitText = VLC - > generaltexth - > quests [ missionType - 1 ] [ 1 ] [ textOption ] ;
completedText = VLC - > generaltexth - > quests [ missionType - 1 ] [ 2 ] [ textOption ] ;
}
else
firstVisitText = VLC - > generaltexth - > seerEmpty [ textOption ] ;
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
{
2010-02-04 22:34:20 +02:00
cb - > removeObject ( id ) ;
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 ( ) ;
2009-03-14 19:19:53 +02:00
if ( ! hasVisited ( h - > tempOwner ) )
2009-02-20 14:39:27 +02:00
cb - > setObjProperty ( id , 10 , h - > tempOwner ) ;
2009-01-11 00:08:18 +02:00
if ( h - > getSecSkillLevel ( ability ) ) //you alredy know this skill
{
iw . text < < std : : pair < ui8 , ui32 > ( 11 , 172 ) ;
2009-07-09 22:15:22 +03:00
iw . text . addReplacement ( MetaString : : SEC_SKILL_NAME , ability ) ;
2009-01-11 00:08:18 +02:00
}
else if ( h - > secSkills . size ( ) > = SKILL_PER_HERO ) //already all skills slots used
{
iw . text < < std : : pair < ui8 , ui32 > ( 11 , 173 ) ;
2009-07-09 22:15:22 +03:00
iw . text . addReplacement ( MetaString : : SEC_SKILL_NAME , ability ) ;
2009-01-11 00:08:18 +02:00
}
else //give sec skill
{
iw . components . push_back ( Component ( 1 , ability , 1 , 0 ) ) ;
iw . text < < std : : pair < ui8 , ui32 > ( 11 , 171 ) ;
2009-07-09 22:15:22 +03:00
iw . text . addReplacement ( MetaString : : SEC_SKILL_NAME , ability ) ;
2009-01-11 00:08:18 +02:00
cb - > changeSecSkill ( h - > id , ability , 1 , true ) ;
}
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 ] ;
2009-03-14 19:19:53 +02:00
if ( hasVisited ( cb - > getCurrentPlayer ( ) ) ) //TODO: use local player, not current
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 ( ) ) ;
if ( h & & h - > getSecSkillLevel ( ability ) ) //hero knows that ability
2009-02-20 14:39:27 +02:00
hoverName + = " \n \n " + VLC - > generaltexth - > allTexts [ 357 ] ; // (Already learned)
}
return hoverName ;
}
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 ) ;
2009-02-04 15:40:54 +02:00
int messageID , bonusType , bonusVal ;
2009-04-24 00:09:10 +03:00
int bonusMove = 0 , sound = - 1 ;
2009-02-04 15:40:54 +02:00
InfoWindow iw ;
iw . player = h - > tempOwner ;
2009-02-05 11:49:45 +02:00
GiveBonus gbonus ;
2010-02-10 04:56:00 +02:00
gbonus . id = h - > id ;
2010-05-02 21:20:26 +03:00
gbonus . bonus . duration = Bonus : : ONE_BATTLE ;
gbonus . bonus . source = Bonus : : OBJECT ;
2009-02-05 11:49:45 +02:00
gbonus . bonus . id = 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 )
{
2009-07-19 10:16:33 +03:00
case 11 : //buoy
messageID = 21 ;
2009-07-26 06:33:13 +03:00
sound = 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 ;
gbonus . bdescr < < std : : pair < ui8 , ui32 > ( 6 , 94 ) ;
break ;
2009-02-04 15:40:54 +02:00
case 14 : //swan pond
messageID = 29 ;
2009-04-24 00:09:10 +03:00
sound = 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 ;
gbonus . bdescr < < std : : pair < ui8 , ui32 > ( 6 , 67 ) ;
bonusMove = - h - > movement ;
break ;
2009-02-04 15:40:54 +02:00
case 28 : //Faerie Ring
messageID = 49 ;
2009-04-24 00:09:10 +03:00
sound = 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 ;
gbonus . bdescr < < std : : pair < ui8 , ui32 > ( 6 , 71 ) ;
2009-02-04 15:40:54 +02:00
break ;
case 30 : //fountain of fortune
messageID = 55 ;
2009-04-24 00:09:10 +03:00
sound = 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 ;
gbonus . bdescr < < std : : pair < ui8 , ui32 > ( 6 , 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 ;
case 38 : //idol of fortune
messageID = 62 ;
2009-11-30 18:14:41 +02:00
sound = soundBase : : experience ;
2010-05-02 21:20:26 +03:00
2009-02-05 11:49:45 +02:00
gbonus . bonus . val = 1 ;
gbonus . bdescr < < std : : pair < ui8 , ui32 > ( 6 , 68 ) ;
2010-05-02 21:20:26 +03:00
if ( cb - > getDate ( 1 ) = = 7 ) //7th day of week
{
gbonus . bonus . type = Bonus : : MORALE ;
second = true ;
secondBonus = gbonus . bonus ;
secondBonus . type = Bonus : : LUCK ;
}
else
{
gbonus . bonus . type = ( cb - > getDate ( 1 ) % 2 ) ? Bonus : : LUCK : Bonus : : MORALE ;
}
2009-02-05 11:49:45 +02:00
break ;
2009-07-19 10:16:33 +03:00
case 52 : //Mermaid
messageID = 83 ;
sound = 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 ;
gbonus . bdescr < < std : : pair < ui8 , ui32 > ( 6 , 72 ) ;
break ;
2009-02-05 11:49:45 +02:00
case 64 : //Rally Flag
2009-04-24 00:09:10 +03:00
sound = 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 ;
gbonus . bdescr < < std : : pair < ui8 , ui32 > ( 6 , 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 ;
case 56 : //oasis
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 ;
gbonus . bdescr < < std : : pair < ui8 , ui32 > ( 6 , 95 ) ;
bonusMove = 800 ;
break ;
case 96 : //temple
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 ;
2009-02-05 11:49:45 +02:00
if ( cb - > getDate ( 1 ) = = 7 ) //sunday
{
gbonus . bonus . val = 2 ;
gbonus . bdescr < < std : : pair < ui8 , ui32 > ( 6 , 97 ) ;
}
else
{
gbonus . bonus . val = 1 ;
gbonus . bdescr < < std : : pair < ui8 , ui32 > ( 6 , 96 ) ;
}
break ;
case 110 : //Watering Hole
2009-04-24 00:09:10 +03:00
sound = 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 ;
gbonus . bdescr < < std : : pair < ui8 , ui32 > ( 6 , 100 ) ;
bonusMove = 400 ;
break ;
case 31 : //Fountain of Youth
2009-04-24 00:09:10 +03:00
sound = 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 ;
gbonus . bdescr < < std : : pair < ui8 , ui32 > ( 6 , 103 ) ;
bonusMove = 400 ;
2009-02-04 15:40:54 +02:00
break ;
2009-08-11 10:50:29 +03:00
case 94 : //Stables TODO: upgrade Cavaliers
sound = soundBase : : horse20 ;
2010-07-07 15:20:15 +03:00
CCreatureSet creatures ;
2010-05-02 21:20:26 +03:00
for ( TSlots : : const_iterator i = h - > Slots ( ) . begin ( ) ; i ! = h - > Slots ( ) . end ( ) ; + + i )
2009-08-15 19:12:30 +03:00
{
2010-04-02 05:07:40 +03:00
if ( i - > second . type - > idNumber = = 10 )
2010-07-07 15:20:15 +03:00
creatures . slots . insert ( * i ) ;
2009-08-15 19:12:30 +03:00
}
2010-07-07 15:20:15 +03:00
if ( creatures . slots . size ( ) )
2009-08-15 19:12:30 +03:00
{
2010-07-07 15:20:15 +03:00
messageID = 138 ;
cb - > takeCreatures ( h - > id , creatures . slots ) ;
for ( std : : map < TSlot , CStackInstance > : : iterator i = creatures . slots . begin ( ) ; i ! = creatures . slots . end ( ) ; i + + )
2009-08-15 19:12:30 +03:00
{
2010-07-07 15:20:15 +03:00
i - > second . setType ( 11 ) ;
2009-08-15 19:12:30 +03:00
}
2010-07-07 15:20:15 +03:00
cb - > giveCreatures ( h - > id , h , creatures ) ; //suboptimal again, but creature sets are screwed in general
2009-08-15 19:12:30 +03:00
}
2010-07-07 15:20:15 +03:00
else
messageID = 137 ;
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 ;
2009-08-11 10:50:29 +03:00
gbonus . bdescr < < std : : pair < ui8 , ui32 > ( 6 , 100 ) ;
break ;
2009-02-04 15:40:54 +02:00
}
if ( visited )
{
2009-08-11 10:50:29 +03:00
if ( ID = = 64 | | ID = = 96 | | ID = = 56 | | ID = = 52 | | ID = = 94 )
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 )
2009-02-05 11:49:45 +02:00
iw . components . push_back ( Component ( 8 , 0 , gbonus . bonus . val , 0 ) ) ;
2010-05-02 21:20:26 +03:00
if ( gbonus . bonus . type = = Bonus : : LUCK | | secondBonus . type = = Bonus : : LUCK )
2009-02-05 11:49:45 +02:00
iw . components . push_back ( Component ( 9 , 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 ) ;
}
}
2009-04-24 00:09:10 +03:00
iw . soundID = sound ;
2009-02-04 15:40:54 +02:00
iw . text < < std : : pair < ui8 , ui32 > ( 11 , messageID ) ;
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 ] ;
if ( h )
{
2010-05-02 21:20:26 +03:00
if ( ! h - > hasBonusFrom ( Bonus : : OBJECT , ID ) )
2009-02-06 13:15:39 +02:00
hoverName + = " " + VLC - > generaltexth - > allTexts [ 353 ] ; //not visited
else
hoverName + = " " + VLC - > generaltexth - > allTexts [ 352 ] ; //visited
}
return hoverName ;
}
2009-07-19 10:16:33 +03:00
void CGBonusingObject : : initObj ( )
{
2009-07-20 01:16:07 +03:00
if ( ID = = 11 | | ID = = 52 ) //Buoy / Mermaid
2009-07-19 10:16:33 +03:00
{
blockVisit = true ;
}
}
2009-09-23 15:42:14 +03:00
void CGMagicSpring : : onHeroVisit ( const CGHeroInstance * h ) const
{
int messageID ;
InfoWindow iw ;
iw . player = h - > tempOwner ;
iw . soundID = soundBase : : GENIE ;
if ( ! visited )
{
if ( h - > mana > h - > manaLimit ( ) )
messageID = 76 ;
else
{
messageID = 74 ;
cb - > setManaPoints ( h - > id , 2 * h - > manaLimit ( ) ) ;
2010-05-02 21:20:26 +03:00
cb - > setObjProperty ( id , ObjProperty : : VISITED , true ) ;
2009-09-23 15:42:14 +03:00
}
}
else
messageID = 75 ;
iw . text < < std : : pair < ui8 , ui32 > ( 11 , messageID ) ;
cb - > showInfoDialog ( & iw ) ;
}
const std : : string & CGMagicSpring : : getHoverText ( ) const
{
hoverName = VLC - > generaltexth - > names [ ID ] ;
if ( ! visited )
hoverName + = " " + VLC - > generaltexth - > allTexts [ 353 ] ; //not visited
else
hoverName + = " " + VLC - > generaltexth - > allTexts [ 352 ] ; //visited
return hoverName ;
}
2009-02-06 13:15:39 +02:00
void CGMagicWell : : onHeroVisit ( const CGHeroInstance * h ) const
{
int message ;
InfoWindow iw ;
2009-04-24 00:09:10 +03:00
iw . soundID = soundBase : : faerie ;
2009-02-06 13:15:39 +02:00
iw . player = h - > tempOwner ;
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
{
message = 78 ;
}
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 ;
}
iw . text < < std : : pair < ui8 , ui32 > ( 11 , message ) ; //"A second drink at the well in one day will not help you."
cb - > showInfoDialog ( & iw ) ;
}
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 ( )
{
2009-11-24 22:29:50 +02:00
blockVisit = ( ID = = 6 ) ; //block only if it's really pandora's box (events also derive from that class)
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 ) ;
cb - > showBlockingDialog ( & bd , boost : : bind ( & CGPandoraBox : : open , this , h , _1 ) ) ;
}
2009-08-17 13:47:08 +03:00
2009-08-16 18:39:18 +03:00
void CGPandoraBox : : open ( const CGHeroInstance * h , ui32 accept ) const
{
if ( accept )
{
2010-05-02 21:20:26 +03:00
if ( stacksCount ( ) > 0 ) //if pandora's box is protected by army
2009-08-16 18:39:18 +03:00
{
InfoWindow iw ;
iw . player = h - > tempOwner ;
iw . text . addTxt ( MetaString : : ADVOB_TXT , 16 ) ;
cb - > showInfoDialog ( & iw ) ;
2009-09-13 01:17:23 +03:00
cb - > startBattleI ( h , this , boost : : bind ( & CGPandoraBox : : endBattle , this , h , _1 ) ) ; //grants things after battle
2009-08-16 18:39:18 +03:00
}
2009-08-17 13:47:08 +03:00
else if ( message . size ( ) = = 0 & & resources . size ( ) = = 0
& & primskills . size ( ) = = 0 & & abilities . size ( ) = = 0
& & abilityLevels . size ( ) = = 0 & & artifacts . size ( ) = = 0
2010-05-02 21:20:26 +03:00
& & spells . size ( ) = = 0 & & creatures . Slots ( ) . size ( ) > 0
2009-08-17 13:47:08 +03:00
& & gainedExp = = 0 & & manaDiff = = 0 & & moraleDiff = = 0 & & luckDiff = = 0 ) //if it gives nothing without battle
2009-08-16 18:39:18 +03:00
{
InfoWindow iw ;
iw . player = h - > tempOwner ;
iw . text . addTxt ( MetaString : : ADVOB_TXT , 15 ) ;
cb - > showInfoDialog ( & iw ) ;
}
2009-08-17 13:47:08 +03:00
else //if it gives something without battle
2009-08-16 18:39:18 +03:00
{
giveContents ( h , false ) ;
}
}
}
2009-08-17 13:47:08 +03:00
2009-08-19 09:56:53 +03:00
void CGPandoraBox : : endBattle ( const CGHeroInstance * h , BattleResult * result ) const
{
if ( result - > winner )
return ;
giveContents ( h , true ) ;
}
2009-08-16 18:39:18 +03:00
void CGPandoraBox : : giveContents ( const CGHeroInstance * h , bool afterBattle ) const
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 ;
for ( int i = 0 ; i < primskills . size ( ) ; i + + )
{
if ( primskills [ i ] )
{
changesPrimSkill = true ;
break ;
}
}
if ( gainedExp | | changesPrimSkill | | abilities . size ( ) )
{
2010-07-26 01:47:59 +03:00
int expVal = gainedExp * ( 100 + h - > getSecSkillLevel ( 21 ) * 5 ) / 100.0f ;
2009-04-21 01:57:07 +03:00
getText ( iw , afterBattle , 175 , h ) ;
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 exp
2010-07-26 01:47:59 +03:00
if ( expVal )
cb - > changePrimSkill ( h - > id , 4 , expVal , false ) ;
2009-04-21 01:57:07 +03:00
//give prim skills
for ( int i = 0 ; i < primskills . size ( ) ; i + + )
if ( primskills [ i ] )
cb - > changePrimSkill ( h - > id , i , primskills [ i ] , false ) ;
//give sec skills
for ( int i = 0 ; i < abilities . size ( ) ; i + + )
{
int curLev = h - > getSecSkillLevel ( abilities [ i ] ) ;
if ( curLev & & curLev < abilityLevels [ i ]
| | h - > secSkills . size ( ) < SKILL_PER_HERO )
{
cb - > changeSecSkill ( h - > id , abilities [ i ] , abilityLevels [ i ] , true ) ;
}
}
}
2009-04-23 18:48:53 +03:00
if ( spells . size ( ) )
{
std : : set < ui32 > spellsToGive ;
iw . components . clear ( ) ;
for ( int i = 0 ; i < spells . size ( ) ; i + + )
{
iw . components . push_back ( Component ( Component : : SPELL , spells [ i ] , 0 , 0 ) ) ;
spellsToGive . insert ( spells [ i ] ) ;
}
if ( spellsToGive . size ( ) )
{
cb - > changeSpells ( h - > id , true , spellsToGive ) ;
cb - > showInfoDialog ( & iw ) ;
}
}
2009-04-21 01:57:07 +03:00
if ( manaDiff )
{
2009-04-23 18:48:53 +03:00
getText ( iw , afterBattle , 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 )
{
2009-04-23 18:48:53 +03:00
getText ( iw , afterBattle , 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 ;
2010-05-02 21:20:26 +03:00
gb . bonus = Bonus ( Bonus : : ONE_BATTLE , Bonus : : MORALE , Bonus : : OBJECT , moraleDiff , id , " " ) ;
2010-02-10 04:56:00 +02:00
gb . id = h - > id ;
2009-04-21 01:57:07 +03:00
cb - > giveHeroBonus ( & gb ) ;
}
if ( luckDiff )
{
getText ( iw , afterBattle , luckDiff , 180 , 181 , h ) ;
iw . components . push_back ( Component ( Component : : LUCK , 0 , luckDiff , 0 ) ) ;
cb - > showInfoDialog ( & iw ) ;
GiveBonus gb ;
2010-05-02 21:20:26 +03:00
gb . bonus = Bonus ( Bonus : : ONE_BATTLE , Bonus : : LUCK , Bonus : : OBJECT , luckDiff , id , " " ) ;
2010-02-10 04:56:00 +02:00
gb . id = h - > id ;
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 ( ) )
{
getText ( iw , afterBattle , 182 , h ) ;
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 ( ) )
{
getText ( iw , afterBattle , 183 , h ) ;
cb - > showInfoDialog ( & iw ) ;
}
2009-11-24 22:29:50 +02:00
iw . components . clear ( ) ;
// getText(iw,afterBattle,183,h);
2009-04-21 01:57:07 +03:00
for ( int i = 0 ; i < artifacts . size ( ) ; i + + )
{
iw . components . push_back ( Component ( Component : : ARTIFACT , artifacts [ i ] , 0 , 0 ) ) ;
2009-07-16 01:46:00 +03:00
if ( iw . components . size ( ) > = 14 )
{
cb - > showInfoDialog ( & iw ) ;
iw . components . clear ( ) ;
}
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 ] )
cb - > giveResource ( h - > getOwner ( ) , i , resources [ i ] ) ;
for ( int i = 0 ; i < artifacts . size ( ) ; i + + )
cb - > giveHeroArtifact ( artifacts [ i ] , h - > id , - 2 ) ;
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
MetaString loot ;
2009-09-25 18:40:28 +03:00
CCreatureSet ourArmy = creatures ;
2010-05-02 21:20:26 +03:00
for ( TSlots : : const_iterator i = ourArmy . Slots ( ) . begin ( ) ; i ! = ourArmy . Slots ( ) . end ( ) ; i + + )
2009-09-26 12:16:59 +03:00
{ //build list of joined creatures
2010-04-02 05:07:40 +03:00
iw . components . push_back ( Component ( i - > second ) ) ;
2009-09-26 12:16:59 +03:00
loot < < " %s " ;
2010-04-02 05:07:40 +03:00
loot . addReplacement ( i - > second ) ;
2009-09-25 18:40:28 +03:00
}
2009-09-23 15:05:33 +03:00
2010-05-02 21:20:26 +03:00
if ( ourArmy . Slots ( ) . size ( ) = = 1 & & ourArmy . Slots ( ) . begin ( ) - > second . count = = 1 )
2009-09-26 12:16:59 +03:00
iw . text . addTxt ( MetaString : : ADVOB_TXT , 185 ) ;
else
iw . text . addTxt ( MetaString : : ADVOB_TXT , 186 ) ;
iw . text . addReplacement ( loot . buildList ( ) ) ;
iw . text . addReplacement ( h - > name ) ;
cb - > showInfoDialog ( & iw ) ;
cb - > giveCreatures ( id , h , ourArmy ) ;
2009-09-23 15:05:33 +03:00
}
2009-07-16 01:46:00 +03:00
if ( ! afterBattle & & message . size ( ) )
2009-04-21 01:57:07 +03:00
{
iw . text < < message ;
cb - > showInfoDialog ( & iw ) ;
}
2009-08-16 18:39:18 +03:00
cb - > removeObject ( id ) ;
2009-04-21 01:57:07 +03:00
}
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
}
2009-08-19 09:56:53 +03:00
void CGEvent : : onHeroVisit ( const CGHeroInstance * h ) const
{
if ( ! ( availableFor & ( 1 < < h - > tempOwner ) ) )
return ;
if ( cb - > getPlayerSettings ( h - > tempOwner ) - > human )
{
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 ) ;
2009-09-13 01:17:23 +03:00
cb - > startBattleI ( h , this , boost : : bind ( & CGEvent : : endBattle , this , h , _1 ) ) ;
2009-08-19 09:56:53 +03:00
}
else
{
giveContents ( h , false ) ;
}
}
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 )
{
case 58 : //redwood observatory
case 60 : //pillar of fire
{
iw . soundID = soundBase : : LIGHTHOUSE ;
iw . text . addTxt ( MetaString : : ADVOB_TXT , 98 + ( ID = = 60 ) ) ;
FoWChange fw ;
fw . player = h - > tempOwner ;
fw . mode = 1 ;
cb - > getTilesInRange ( fw . tiles , pos , 20 , h - > tempOwner , 1 ) ;
cb - > sendAndApply ( & fw ) ;
break ;
}
case 15 : //cover of darkness
{
iw . text . addTxt ( MetaString : : ADVOB_TXT , 31 ) ;
2010-06-19 12:13:10 +03:00
hideTiles ( h - > tempOwner , 20 ) ;
2010-06-06 09:05:39 +03:00
break ;
}
}
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
{
if ( spell = = 255 )
{
tlog1 < < " Not initialized shrine visited! \n " ;
return ;
}
2009-03-14 19:19:53 +02:00
if ( ! hasVisited ( h - > tempOwner ) )
cb - > setObjProperty ( id , 10 , h - > tempOwner ) ;
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 < < " . " ;
if ( ! h - > getArt ( 17 ) ) //no spellbook
{
iw . text . addTxt ( MetaString : : ADVOB_TXT , 131 ) ;
}
else if ( ID = = 90 & & ! h - > getSecSkillLevel ( 7 ) ) //it's third level spell and hero doesn't have wisdom
{
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
{
std : : set < ui32 > spells ;
spells . insert ( spell ) ;
2010-06-21 07:43:10 +03:00
cb - > changeSpells ( h - > id , 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 ( )
{
if ( spell = = 255 ) //spell not set
{
int level = ID - 87 ;
2009-09-24 22:28:26 +03:00
std : : vector < ui16 > possibilities ;
cb - > getAllowedSpells ( possibilities , level ) ;
2009-03-14 13:25:25 +02:00
if ( ! possibilities . size ( ) )
{
tlog1 < < " Error: cannot init shrine, no allowed spells! \n " ;
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 ] ;
if ( hasVisited ( cb - > getCurrentPlayer ( ) ) ) //TODO: use local player, not current
{
hoverName + = " \n " + VLC - > generaltexth - > allTexts [ 355 ] ; // + (learn %s)
boost : : algorithm : : replace_first ( hoverName , " %s " , VLC - > spellh - > spells [ spell ] . name ) ;
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
if ( ID = = 59 )
{
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
if ( ID = = 59 )
cb - > removeObject ( id ) ;
2009-04-08 22:55:50 +03:00
}
void CGScholar : : giveAnyBonus ( const CGHeroInstance * h ) const
{
}
void CGScholar : : onHeroVisit ( const CGHeroInstance * h ) const
{
int type = bonusType ;
int bid = bonusID ;
//check if the bonus if applicable, if not - give primary skill (always possible)
int ssl = h - > getSecSkillLevel ( bid ) ; //current sec skill level, used if bonusType == 1
if ( ( type = = 1
& & ( ( ssl = = 3 ) | | ( ! ssl & & h - > secSkills . size ( ) = = SKILL_PER_HERO ) ) ) ////hero already has expert level in the skill or (don't know skill and doesn't have free slot)
2009-09-26 00:11:13 +03:00
| | ( type = = 2 & & ( ! h - > getArt ( 17 ) | | vstd : : contains ( h - > spells , ( ui32 ) bid ) ) ) ) //hero doesn't have a spellbook or already knows the spell
2009-04-08 22:55:50 +03:00
{
type = 0 ;
bid = ran ( ) % PRIMARY_SKILLS ;
}
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 )
{
case 0 :
cb - > changePrimSkill ( h - > id , 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 ;
case 1 :
2009-06-10 03:06:35 +03:00
cb - > changeSecSkill ( h - > id , bid , + 1 ) ;
iw . components . push_back ( Component ( Component : : SEC_SKILL , bid , ssl + 1 , 0 ) ) ;
2009-04-08 22:55:50 +03:00
break ;
case 2 :
{
std : : set < ui32 > hlp ;
hlp . insert ( bid ) ;
cb - > changeSpells ( h - > id , true , hlp ) ;
iw . components . push_back ( Component ( Component : : SPELL , bid , 0 , 0 ) ) ;
}
break ;
default :
tlog1 < < " Error: wrong bonustype ( " < < ( int ) type < < " ) for Scholar! \n " ;
return ;
}
cb - > showInfoDialog ( & iw ) ;
cb - > removeObject ( id ) ;
}
void CGScholar : : initObj ( )
{
blockVisit = true ;
if ( bonusType = = 255 )
{
bonusType = ran ( ) % 3 ;
switch ( bonusType )
{
case 0 :
bonusID = ran ( ) % PRIMARY_SKILLS ;
break ;
case 1 :
bonusID = ran ( ) % SKILL_QUANTITY ;
break ;
case 2 :
2009-10-23 22:58:21 +03:00
std : : vector < ui16 > possibilities ;
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-05-02 21:20:26 +03:00
if ( h - > tempOwner ! = tempOwner & & stacksCount ( ) > 0 ) {
2009-08-25 18:08:18 +03:00
//TODO: Find a way to apply magic garrison effects in battle.
2009-09-13 01:17:23 +03:00
cb - > startBattleI ( h , this , boost : : bind ( & CGGarrison : : fightOver , this , h , _1 ) ) ;
2009-08-25 18:08:18 +03:00
return ;
}
//New owner.
if ( h - > tempOwner ! = tempOwner )
cb - > setOwner ( id , h - > tempOwner ) ;
2009-09-09 20:49:03 +03:00
cb - > showGarrisonDialog ( id , h - > id , removableUnits , 0 ) ;
2009-08-25 18:08:18 +03:00
}
void CGGarrison : : fightOver ( const CGHeroInstance * h , BattleResult * result ) const
{
if ( result - > winner = = 0 )
onHeroVisit ( h ) ;
}
2009-12-20 19:14:14 +02:00
ui8 CGGarrison : : getPassableness ( ) const
{
return 1 < < tempOwner ;
}
2009-04-16 03:28:54 +03:00
void CGOnceVisitable : : onHeroVisit ( const CGHeroInstance * h ) const
{
2009-04-24 00:09:10 +03:00
int sound = 0 ;
2009-04-16 03:28:54 +03:00
int txtid = - 1 ;
switch ( ID )
{
case 22 : //Corpse
txtid = 37 ;
2009-04-24 00:09:10 +03:00
sound = soundBase : : MYSTERY ;
2009-04-16 03:28:54 +03:00
break ;
case 39 : //Lean To
2009-04-24 00:09:10 +03:00
sound = soundBase : : GENIE ;
2009-04-16 03:28:54 +03:00
txtid = 64 ;
break ;
case 105 : //Wagon
2009-04-24 00:09:10 +03:00
sound = soundBase : : GENIE ;
2009-04-16 03:28:54 +03:00
txtid = 154 ;
break ;
case 108 :
break ;
default :
tlog1 < < " Error: Unknown object ( " < < ID < < " ) treated as CGOnceVisitable! \n " ;
return ;
}
if ( ID = = 108 ) //Warrior's Tomb
{
//ask if player wants to search the Tomb
BlockingDialog bd ( true , false ) ;
2009-04-24 00:09:10 +03:00
sound = soundBase : : GRAVEYARD ;
2009-04-16 03:28:54 +03:00
bd . player = h - > getOwner ( ) ;
bd . text . addTxt ( MetaString : : ADVOB_TXT , 161 ) ;
cb - > showBlockingDialog ( & bd , boost : : bind ( & CGOnceVisitable : : searchTomb , this , h , _1 ) ) ;
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 + + ;
2009-08-20 04:56:00 +03:00
if ( ID = = 105 ) //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
2009-12-01 12:10:42 +02:00
if ( ID = = 22 ) //Corpse
+ + 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 ) ) ;
cb - > giveHeroArtifact ( bonusType , h - > id , - 2 ) ;
2009-12-01 12:10:42 +02:00
iw . text . addTxt ( MetaString : : ADVOB_TXT , txtid ) ;
if ( ID = = 22 ) //Corpse
{
iw . text < < " %s " ;
iw . text . addReplacement ( MetaString : : ART_NAMES , bonusType ) ;
}
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 ) ) ;
cb - > giveResource ( h - > getOwner ( ) , bonusType , bonusVal ) ;
2009-04-16 03:28:54 +03:00
break ;
}
2009-07-12 17:07:36 +03:00
if ( ID = = 105 & & artOrRes = = 1 )
{
iw . text . localStrings . back ( ) . second + + ;
iw . text . addReplacement ( MetaString : : ART_NAMES , bonusType ) ;
}
2009-04-16 03:28:54 +03:00
}
cb - > showInfoDialog ( & iw ) ;
cb - > setObjProperty ( id , 10 , h - > getOwner ( ) ) ;
}
const std : : string & CGOnceVisitable : : getHoverText ( ) const
{
hoverName = VLC - > generaltexth - > names [ ID ] + " " ;
hoverName + = ( hasVisited ( cb - > getCurrentPlayer ( ) )
? ( VLC - > generaltexth - > allTexts [ 352 ] ) //visited
: ( VLC - > generaltexth - > allTexts [ 353 ] ) ) ; //not visited
return hoverName ;
}
void CGOnceVisitable : : initObj ( )
{
switch ( ID )
{
case 22 : //Corpse
{
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 ;
case 39 : //Lean To
{
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
case 108 : //Warrior's Tomb
{
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 ;
case 105 : //Wagon
{
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
}
}
void CGOnceVisitable : : searchTomb ( const CGHeroInstance * h , ui32 accept ) const
{
if ( accept )
{
InfoWindow iw ;
iw . player = h - > getOwner ( ) ;
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
cb - > giveHeroArtifact ( bonusType , h - > id , - 2 ) ;
2009-08-13 04:03:11 +03:00
}
2010-05-02 21:20:26 +03:00
if ( ! h - > hasBonusFrom ( Bonus : : OBJECT , ID ) ) //we don't have modifier from this object yet
2009-08-13 04:03:11 +03:00
{
//ruin morale
GiveBonus gb ;
2010-02-10 04:56:00 +02:00
gb . id = h - > id ;
2010-05-02 21:20:26 +03:00
gb . bonus = Bonus ( Bonus : : ONE_BATTLE , Bonus : : MORALE , Bonus : : OBJECT , - 3 , id , " " ) ;
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 ) ;
cb - > setObjProperty ( id , 10 , h - > getOwner ( ) ) ;
2009-08-11 10:50:29 +03:00
}
}
void CBank : : initObj ( )
{
switch ( ID ) //find apriopriate key
{
case 16 : //bank
index = subID ; break ;
case 24 : //derelict ship
2009-08-24 17:59:24 +03:00
index = 8 ; break ;
2009-08-11 10:50:29 +03:00
case 25 : //utopia
index = 10 ; break ;
case 84 : //crypt
index = 9 ; break ;
case 85 : //shipwreck
index = 7 ; break ;
}
bc = NULL ;
daycounter = 0 ;
multiplier = 1 ;
}
2009-09-17 17:27:28 +03:00
const std : : string & CBank : : getHoverText ( ) const
{
hoverName = VLC - > objh - > creBanksNames [ index ] ;
if ( bc = = NULL )
hoverName + = " " + VLC - > generaltexth - > allTexts [ 352 ] ;
else
hoverName + = " " + VLC - > generaltexth - > allTexts [ 353 ] ;
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 ;
2009-08-23 21:01:08 +03:00
for ( ui8 i = 0 ; i < VLC - > objh - > banksInfo [ index ] . size ( ) ; i + + )
2009-08-24 17:59:24 +03:00
{
2009-12-29 03:07:17 +02:00
if ( var1 < ( chance + = VLC - > objh - > banksInfo [ index ] [ i ] - > chance ) )
2009-08-26 08:08:59 +03:00
{
2009-12-29 03:07:17 +02:00
bc = VLC - > objh - > banksInfo [ index ] [ i ] ;
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
{
cb - > setObjProperty ( id , 14 , ran ( ) ) ; //synchronous reset
2010-06-28 08:07:21 +03:00
ui32 artid ;
2009-08-26 08:08:59 +03:00
for ( ui8 i = 0 ; i < = 3 ; i + + )
2009-10-24 22:21:32 +03:00
{
for ( ui8 n = 0 ; n < bc - > artifacts [ i ] ; n + + ) //new function using proper randomization algorithm
2010-06-28 08:07:21 +03:00
{
cb - > setObjProperty ( id , 18 + i , ran ( ) ) ; //synchronic
2009-08-24 17:59:24 +03:00
}
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 )
{
case 11 : //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 ;
2009-08-26 08:08:59 +03:00
case 12 : //multiplier, in percent
2009-08-19 09:56:53 +03:00
multiplier = ( ( float ) val ) / 100 ;
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 ;
2009-08-19 09:56:53 +03:00
case 14 :
2009-10-24 22:21:32 +03:00
reset ( val % 100 ) ;
2009-08-19 09:56:53 +03:00
break ;
case 15 :
bc = NULL ;
break ;
2010-03-24 16:58:17 +02:00
case 16 : //remove rewards from Derelict Ship
2009-08-23 18:02:21 +03:00
artifacts . clear ( ) ;
break ;
2009-08-26 08:08:59 +03:00
case 17 : //set ArmedInstance army
{
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 )
2010-05-02 21:20:26 +03:00
setCreature ( i , bc - > guards [ 0 ] . first , bc - > guards [ 0 ] . second / 5 ) ;
setCreature ( 4 , 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
{
2009-10-24 22:21:32 +03:00
std : : vector < std : : pair < ui16 , ui32 > > : : const_iterator it ;
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
{
2010-03-24 16:58:17 +02:00
for ( it = bc - > guards . begin ( ) ; it ! = bc - > guards . end ( ) ; it + + )
{
2010-05-02 21:20:26 +03:00
setCreature ( stacksCount ( ) , it - > first , it - > 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
{
2010-05-02 21:20:26 +03:00
setCreature ( 0 , bc - > guards [ 0 ] . first , bc - > guards [ 0 ] . second / 2 ) ;
2010-06-26 11:31:31 +03:00
setCreature ( 1 , bc - > guards [ 1 ] . first , bc - > guards [ 1 ] . second / 2 ) ;
setCreature ( 2 , bc - > guards [ 2 ] . first + upgraded , bc - > guards [ 2 ] . second ) ;
setCreature ( 3 , bc - > guards [ 1 ] . first , bc - > guards [ 1 ] . second / 2 ) ;
setCreature ( 4 , bc - > guards [ 0 ] . first , bc - > guards [ 0 ] . second - ( bc - > guards [ 0 ] . second / 2 ) ) ;
}
else //split both stacks
{
for ( int i = 0 ; i < 3 ; + + i ) //skellies
setCreature ( 2 * i , bc - > guards [ 0 ] . first , bc - > guards [ 0 ] . second / 3 ) ;
for ( int i = 0 ; i < 2 ; + + i ) //zombies
setCreature ( 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 :
2009-10-26 11:11:10 +02:00
tlog2 < < " 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 ;
2009-10-24 22:21:32 +03:00
case 18 : //add Artifact
2010-06-28 08:07:21 +03:00
{
int id = cb - > getArtSync ( val , CArtifact : : ART_TREASURE ) ;
artifacts . push_back ( id ) ;
cb - > erasePickedArt ( id ) ;
break ;
}
case 19 : //add Artifact
{
int id = cb - > getArtSync ( val , CArtifact : : ART_MINOR ) ;
artifacts . push_back ( id ) ;
cb - > erasePickedArt ( id ) ;
2009-10-24 22:21:32 +03:00
break ;
2010-06-28 08:07:21 +03:00
}
case 20 : //add Artifact
{
int id = cb - > getArtSync ( val , CArtifact : : ART_MAJOR ) ;
artifacts . push_back ( id ) ;
cb - > erasePickedArt ( id ) ;
break ;
}
case 21 : //add Artifact
{
int id = cb - > getArtSync ( val , CArtifact : : ART_RELIC ) ;
artifacts . push_back ( id ) ;
cb - > erasePickedArt ( id ) ;
break ;
}
2009-08-11 10:50:29 +03:00
}
}
2009-08-23 18:02:21 +03:00
void CBank : : newTurn ( ) const
2009-08-11 10:50:29 +03:00
{
if ( bc = = NULL )
{
2009-09-25 18:40:28 +03:00
if ( cb - > getDate ( 0 ) = = 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 ( ) ;
2009-09-25 18:40:28 +03:00
cb - > setObjProperty ( id , 11 , 0 ) ; //daycounter 0
if ( ID = = 24 & & cb - > getDate ( 0 ) > 1 )
2010-03-24 16:58:17 +02:00
{
cb - > setObjProperty ( id , 12 , 0 ) ; //ugly hack to make derelict ships usable only once
cb - > setObjProperty ( id , 16 , 0 ) ;
}
2009-08-11 10:50:29 +03:00
}
else
2009-08-26 08:08:59 +03:00
cb - > setObjProperty ( id , 11 , 1 ) ; //daycounter++
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 )
{
case 16 : //generic bank
banktext = 32 ;
break ;
case 24 :
banktext = 41 ;
break ;
case 25 : //utopia
banktext = 47 ;
break ;
case 84 : //crypt
banktext = 119 ;
break ;
case 85 : //shipwreck
banktext = 122 ;
break ;
}
BlockingDialog bd ( true , false ) ;
bd . player = h - > getOwner ( ) ;
bd . soundID = soundBase : : DANGER ;
2009-09-17 17:27:28 +03:00
bd . text < < VLC - > generaltexth - > advobtxt [ banktext ] ;
if ( ID = = 16 )
bd . text . addReplacement ( VLC - > objh - > creBanksNames [ index ] ) ;
2009-08-11 10:50:29 +03:00
cb - > showBlockingDialog ( & bd , boost : : bind ( & CBank : : fightGuards , this , h , _1 ) ) ;
}
else
{
InfoWindow iw ;
iw . soundID = soundBase : : GRAVEYARD ;
iw . player = h - > getOwner ( ) ;
2010-03-24 16:58:17 +02:00
if ( ID = = 84 ) //morale penalty for empty Crypt
{
GiveBonus gbonus ;
gbonus . id = h - > id ;
2010-05-02 21:20:26 +03:00
gbonus . bonus . duration = Bonus : : ONE_BATTLE ;
gbonus . bonus . source = Bonus : : OBJECT ;
2010-03-24 16:58:17 +02:00
gbonus . bonus . id = ID ;
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 ] ;
iw . text . addReplacement ( VLC - > objh - > creBanksNames [ index ] ) ;
}
2009-04-16 03:28:54 +03:00
cb - > showInfoDialog ( & iw ) ;
2009-08-11 10:50:29 +03:00
}
}
void CBank : : fightGuards ( const CGHeroInstance * h , ui32 accept ) const
{
if ( accept )
{
2009-08-26 08:08:59 +03:00
cb - > setObjProperty ( id , 17 , ran ( ) ) ; //get army
2009-09-13 01:17:23 +03:00
cb - > startBattleI ( h , this , boost : : bind ( & CBank : : endBattle , this , h , _1 ) , true ) ;
2009-08-11 10:50:29 +03:00
}
}
2009-08-19 09:56:53 +03:00
void CBank : : endBattle ( const CGHeroInstance * h , const BattleResult * result ) const
2009-08-11 10:50:29 +03:00
{
if ( result - > winner = = 0 )
{
int textID = - 1 ;
InfoWindow iw ;
2009-09-16 19:16:57 +03:00
iw . player = h - > getOwner ( ) ;
MetaString loot ;
2009-08-11 10:50:29 +03:00
switch ( ID )
{
2009-12-29 19:15:03 +02:00
case 16 : case 25 :
2009-08-11 10:50:29 +03:00
textID = 34 ;
break ;
case 24 : //derelict ship
2010-03-24 16:58:17 +02:00
if ( multiplier )
2009-08-11 10:50:29 +03:00
textID = 43 ;
else
{
2009-12-29 19:15:03 +02:00
GiveBonus gbonus ;
2010-02-10 04:56:00 +02:00
gbonus . id = h - > id ;
2010-05-02 21:20:26 +03:00
gbonus . bonus . duration = Bonus : : ONE_BATTLE ;
gbonus . bonus . source = Bonus : : OBJECT ;
2009-12-29 19:15:03 +02:00
gbonus . bonus . id = ID ;
2010-03-24 16:58:17 +02:00
gbonus . bdescr < < " \n " < < VLC - > generaltexth - > arraytxt [ 101 ] ;
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 ;
2009-12-29 19:15:03 +02:00
cb - > giveHeroBonus ( & gbonus ) ;
2009-08-11 10:50:29 +03:00
textID = 42 ;
2010-03-24 16:58:17 +02:00
iw . components . push_back ( Component ( Component : : MORALE , 0 , - 1 , 0 ) ) ;
2009-08-11 10:50:29 +03:00
}
break ;
2009-12-29 19:15:03 +02:00
case 84 : //Crypt
if ( bc - > resources . size ( ) ! = 0 )
textID = 121 ;
else
{
iw . components . push_back ( Component ( Component : : MORALE , 0 , - 1 , 0 ) ) ;
GiveBonus gbonus ;
2010-02-10 04:56:00 +02:00
gbonus . id = h - > id ;
2010-05-02 21:20:26 +03:00
gbonus . bonus . duration = Bonus : : ONE_BATTLE ;
gbonus . bonus . source = Bonus : : OBJECT ;
2009-12-29 19:15:03 +02:00
gbonus . bonus . id = ID ;
gbonus . bdescr < < " \n " < < VLC - > generaltexth - > arraytxt [ ID ] ;
2010-05-02 21:20:26 +03:00
gbonus . bonus . type = Bonus : : MORALE ;
2009-12-29 19:15:03 +02:00
gbonus . bonus . val = - 1 ;
cb - > giveHeroBonus ( & gbonus ) ;
textID = 120 ;
iw . components . push_back ( Component ( Component : : MORALE , 0 , - 1 , 0 ) ) ;
}
break ;
2009-08-11 10:50:29 +03:00
case 85 : //shipwreck
2010-03-24 16:58:17 +02:00
if ( bc - > resources . size ( ) )
2009-08-11 10:50:29 +03:00
textID = 124 ;
else
2010-03-24 16:58:17 +02:00
textID = 123 ;
2009-08-11 10:50:29 +03:00
break ;
}
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 + + )
{
if ( bc - > resources [ it ] ! = 0 )
{
iw . components . push_back ( Component ( Component : : RESOURCE , it , bc - > resources [ it ] , 0 ) ) ;
loot < < " %d %s " ;
loot . addReplacement ( iw . components . back ( ) . val ) ;
loot . addReplacement ( MetaString : : RES_NAMES , iw . components . back ( ) . subtype ) ;
cb - > giveResource ( h - > getOwner ( ) , it , bc - > resources [ it ] ) ;
}
}
2009-08-11 10:50:29 +03:00
}
2009-08-20 13:07:23 +03:00
//grant artifacts
2009-08-26 08:08:59 +03:00
for ( std : : vector < ui32 > : : const_iterator it = artifacts . begin ( ) ; it ! = artifacts . end ( ) ; it + + )
2009-08-11 10:50:29 +03:00
{
iw . components . push_back ( Component ( Component : : ARTIFACT , * it , 0 , 0 ) ) ;
2009-09-16 19:16:57 +03:00
loot < < " %s " ;
loot . addReplacement ( MetaString : : ART_NAMES , * it ) ;
2009-08-26 08:08:59 +03:00
cb - > giveHeroArtifact ( * it , h - > id , - 2 ) ;
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
{
2009-09-17 09:19:27 +03:00
if ( textID = = 34 )
{
iw . text . addTxt ( MetaString : : ADVOB_TXT , 34 ) ; //Heaving defeated %s, you discover %s
iw . text . addReplacement ( MetaString : : CRE_PL_NAMES , result - > casualties [ 1 ] . begin ( ) - > first ) ;
iw . text . addReplacement ( loot . buildList ( ) ) ;
}
else
iw . text . addTxt ( MetaString : : ADVOB_TXT , textID ) ;
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 ;
2009-08-19 09:56:53 +03:00
for ( std : : vector < std : : pair < ui16 , ui32 > > : : const_iterator it = bc - > creatures . begin ( ) ; it ! = bc - > creatures . end ( ) ; it + + )
2009-08-11 10:50:29 +03:00
{
2010-04-02 05:07:40 +03:00
int slot = ourArmy . getSlotFor ( it - > first ) ;
ourArmy . addToSlot ( slot , it - > first , it - > second ) ;
2009-08-11 10:50:29 +03:00
}
2010-05-02 21:20:26 +03:00
for ( TSlots : : const_iterator i = ourArmy . Slots ( ) . begin ( ) ; i ! = ourArmy . Slots ( ) . end ( ) ; i + + )
2009-09-17 09:19:27 +03:00
{
2010-04-02 05:07:40 +03:00
iw . components . push_back ( Component ( i - > second ) ) ;
2009-09-17 09:19:27 +03:00
loot < < " %s " ;
2010-04-02 05:07:40 +03:00
loot . addReplacement ( i - > 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-05-02 21:20:26 +03: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 ) ;
iw . text . addReplacement ( loot . buildList ( ) ) ;
iw . text . addReplacement ( h - > name ) ;
cb - > showInfoDialog ( & iw ) ;
2009-09-23 15:05:33 +03:00
cb - > giveCreatures ( id , h , ourArmy ) ;
2009-09-17 09:19:27 +03:00
}
2009-09-01 17:36:48 +03:00
cb - > setObjProperty ( id , 15 , 0 ) ; //bc = NULL
2009-08-11 10:50:29 +03:00
}
2009-09-16 19:16:57 +03:00
else //in case of defeat
2009-10-24 22:21:32 +03:00
initialize ( ) ;
2009-08-11 10:50:29 +03:00
}
2009-09-24 20:54:02 +03:00
void CGPyramid : : initObj ( )
{
//would be nice to do that only once
if ( ! pyramidConfig . guards . size ( ) )
{
pyramidConfig . level = 1 ;
pyramidConfig . chance = 100 ;
pyramidConfig . upgradeChance = 0 ;
for ( int i = 0 ; i < 2 ; + + i )
{
pyramidConfig . guards . push_back ( std : : pair < ui16 , ui32 > ( 116 , 20 ) ) ;
pyramidConfig . guards . push_back ( std : : pair < ui16 , ui32 > ( 117 , 10 ) ) ;
}
pyramidConfig . combatValue ; //how hard are guards of this level
pyramidConfig . value ; //overall value of given things
pyramidConfig . rewardDifficulty ; //proportion of reward value to difficulty of guards; how profitable is this creature Bank config
pyramidConfig . easiest ; //?!?
}
bc = & pyramidConfig ;
2009-09-25 07:05:01 +03:00
std : : vector < ui16 > available ;
cb - > getAllowedSpells ( available , 5 ) ;
spell = ( available [ rand ( ) % available . size ( ) ] ) ;
2009-09-24 20:54:02 +03:00
}
2009-09-25 18:40:28 +03:00
const std : : string & CGPyramid : : getHoverText ( ) const
{
hoverName = VLC - > generaltexth - > names [ ID ] ;
if ( bc = = NULL )
hoverName + = " " + VLC - > generaltexth - > allTexts [ 352 ] ;
else
hoverName + = " " + VLC - > generaltexth - > allTexts [ 353 ] ;
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 ( ) ;
bd . soundID = soundBase : : DANGER ;
bd . text < < VLC - > generaltexth - > advobtxt [ 105 ] ;
cb - > showBlockingDialog ( & bd , boost : : bind ( & CBank : : fightGuards , this , h , _1 ) ) ;
}
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 ;
2010-05-02 21:20:26 +03:00
gb . bonus = Bonus ( Bonus : : ONE_BATTLE , Bonus : : LUCK , Bonus : : OBJECT , - 2 , id , VLC - > generaltexth - > arraytxt [ 70 ] ) ;
2010-02-10 04:56:00 +02:00
gb . id = h - > id ;
2009-09-24 20:54:02 +03:00
cb - > giveHeroBonus ( & gb ) ;
cb - > showInfoDialog ( & iw ) ;
}
}
void CGPyramid : : endBattle ( const CGHeroInstance * h , const BattleResult * result ) const
{
if ( result - > winner = = 0 )
{
InfoWindow iw ;
2009-09-25 18:40:28 +03:00
iw . player = h - > getOwner ( ) ;
2009-09-24 20:54:02 +03:00
iw . text . addTxt ( MetaString : : ADVOB_TXT , 106 ) ;
iw . text . addTxt ( MetaString : : SPELL_NAME , spell ) ;
2009-09-25 18:40:28 +03:00
if ( ! h - > getArt ( 17 ) )
iw . text . addTxt ( MetaString : : ADVOB_TXT , 109 ) ; //no spellbook
else if ( h - > getSecSkillLevel ( 7 ) < 3 )
iw . text . addTxt ( MetaString : : ADVOB_TXT , 108 ) ; //no expert Wisdom
2009-09-24 20:54:02 +03:00
else
{
std : : set < ui32 > spells ;
spells . insert ( spell ) ;
cb - > changeSpells ( h - > id , true , spells ) ;
iw . components . push_back ( Component ( Component : : SPELL , spell , 0 , 0 ) ) ;
}
cb - > showInfoDialog ( & iw ) ;
2009-09-25 18:40:28 +03:00
cb - > setObjProperty ( id , 15 , 0 ) ;
2009-09-24 20:54:02 +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
{
if ( what > = 101 & & what < = ( 100 + PLAYER_LIMIT ) )
2010-07-06 05:10:26 +03:00
playerKeyMap . find ( what - 101 ) - > second . insert ( ( ui8 ) val ) ;
2009-08-11 10:50:29 +03:00
}
2009-04-16 03:28:54 +03:00
2009-08-11 10:50:29 +03:00
bool CGKeys : : wasMyColorVisited ( int player ) const
{
if ( vstd : : contains ( playerKeyMap [ player ] , subID ) ) //creates set if it's not there
return true ;
else
return false ;
}
const std : : string & CGKeymasterTent : : getHoverText ( ) const
{
hoverName = VLC - > generaltexth - > names [ ID ] ;
if ( wasMyColorVisited ( cb - > getCurrentPlayer ( ) ) ) //TODO: use local player, not current
hoverName + = " \n " + VLC - > generaltexth - > allTexts [ 352 ] ;
else
hoverName + = " \n " + VLC - > generaltexth - > allTexts [ 353 ] ;
return hoverName ;
}
void CGKeymasterTent : : onHeroVisit ( const CGHeroInstance * h ) const
{
InfoWindow iw ;
iw . soundID = soundBase : : CAVEHEAD ;
iw . player = h - > getOwner ( ) ;
if ( ! wasMyColorVisited ( h - > getOwner ( ) ) )
{
cb - > setObjProperty ( id , h - > tempOwner + 101 , subID ) ;
iw . text < < std : : pair < ui8 , ui32 > ( 11 , 19 ) ;
2009-04-16 03:28:54 +03:00
}
2009-08-11 10:50:29 +03:00
else
iw . text < < std : : pair < ui8 , ui32 > ( 11 , 20 ) ;
cb - > showInfoDialog ( & iw ) ;
}
void CGBorderGuard : : initObj ( )
{
blockVisit = true ;
2009-05-24 01:57:39 +03:00
}
2009-07-19 04:00:19 +03:00
2009-08-11 10:50:29 +03:00
const std : : string & CGBorderGuard : : getHoverText ( ) const
{
hoverName = VLC - > generaltexth - > names [ ID ] ;
if ( wasMyColorVisited ( cb - > getCurrentPlayer ( ) ) ) //TODO: use local player, not current
hoverName + = " \n " + VLC - > generaltexth - > allTexts [ 352 ] ;
else
hoverName + = " \n " + VLC - > generaltexth - > allTexts [ 353 ] ;
return hoverName ;
}
void CGBorderGuard : : onHeroVisit ( const CGHeroInstance * h ) const
{
if ( wasMyColorVisited ( h - > getOwner ( ) ) )
{
BlockingDialog bd ( true , false ) ;
bd . player = h - > getOwner ( ) ;
bd . soundID = soundBase : : QUEST ;
bd . text . addTxt ( MetaString : : ADVOB_TXT , 17 ) ;
cb - > showBlockingDialog ( & bd , boost : : bind ( & CGBorderGuard : : openGate , this , h , _1 ) ) ;
}
else
{
InfoWindow iw ;
iw . player = h - > getOwner ( ) ;
iw . soundID = soundBase : : CAVEHEAD ;
iw . text < < std : : pair < ui8 , ui32 > ( 11 , 18 ) ;
cb - > showInfoDialog ( & iw ) ;
}
}
void CGBorderGuard : : openGate ( const CGHeroInstance * h , ui32 accept ) const
{
if ( accept )
cb - > removeObject ( id ) ;
}
void CGBorderGate : : onHeroVisit ( const CGHeroInstance * h ) const //TODO: passability
{
if ( ! wasMyColorVisited ( h - > getOwner ( ) ) )
{
2009-12-20 19:14:14 +02:00
InfoWindow iw ;
iw . player = h - > getOwner ( ) ;
2009-08-11 10:50:29 +03:00
iw . text < < std : : pair < ui8 , ui32 > ( 11 , 18 ) ;
cb - > showInfoDialog ( & iw ) ;
}
}
2009-12-20 19:14:14 +02:00
ui8 CGBorderGate : : getPassableness ( ) const
{
ui8 ret = 0 ;
for ( int i = 0 ; i < PLAYER_LIMIT ; i + + )
ret | = wasMyColorVisited ( i ) < < i ;
return ret ;
}
2009-08-11 10:50:29 +03:00
void CGMagi : : initObj ( )
{
if ( ID = = 27 )
{
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
{
if ( ID = = 37 )
{
InfoWindow iw ;
CenterView cv ;
FoWChange fw ;
cv . player = iw . player = fw . player = h - > tempOwner ;
iw . soundID = soundBase : : LIGHTHOUSE ;
iw . player = h - > tempOwner ;
iw . text . addTxt ( MetaString : : ADVOB_TXT , 61 ) ;
cb - > showInfoDialog ( & iw ) ;
fw . mode = 1 ;
2009-08-13 04:03:11 +03:00
std : : vector < si32 > : : iterator it ;
for ( it = eyelist [ subID ] . begin ( ) ; it < eyelist [ subID ] . end ( ) ; it + + )
{
const CGObjectInstance * eye = cb - > getObj ( * it ) ;
2010-06-21 07:43:10 +03:00
cb - > getTilesInRange ( fw . tiles , eye - > pos , 10 , h - > tempOwner , 1 ) ;
2009-08-11 10:50:29 +03:00
cb - > sendAndApply ( & fw ) ;
2009-08-13 04:03:11 +03:00
cv . pos = eye - > pos ;
cv . focusTime = 2000 ;
2009-08-11 10:50:29 +03:00
cb - > sendAndApply ( & cv ) ;
}
2009-08-13 04:03:11 +03:00
cv . pos = h - > getPosition ( false ) ;
2009-08-11 10:50:29 +03:00
cb - > sendAndApply ( & cv ) ;
}
else if ( ID = = 27 )
{
InfoWindow iw ;
iw . player = h - > tempOwner ;
iw . text . addTxt ( MetaString : : ADVOB_TXT , 48 ) ;
cb - > showInfoDialog ( & iw ) ;
}
}
2009-07-19 04:00:19 +03:00
void CGBoat : : initObj ( )
{
hero = NULL ;
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
{
int message ;
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
{
iw . text . addTxt ( 11 , 133 ) ;
}
else
{
2010-05-02 21:20:26 +03:00
giveDummyBonus ( h - > id , Bonus : : ONE_BATTLE ) ;
2009-07-19 10:16:33 +03:00
int xp = 0 ;
SetGarrisons sg ;
2010-05-02 21:20:26 +03:00
sg . garrs [ h - > id ] = h - > getArmy ( ) ;
for ( TSlots : : const_iterator i = h - > Slots ( ) . begin ( ) ; i ! = h - > Slots ( ) . end ( ) ; i + + )
2009-07-19 10:16:33 +03:00
{
2010-04-02 05:07:40 +03:00
int drown = ( int ) ( i - > second . count * 0.3 ) ;
2009-07-19 10:16:33 +03:00
if ( drown )
{
2010-05-02 21:20:26 +03:00
sg . garrs [ h - > id ] . setStackCount ( i - > first , i - > second . count - drown ) ;
xp + = drown * i - > second . type - > valOfBonuses ( Bonus : : STACK_HEALTH ) ;
2009-07-19 10:16:33 +03:00
}
}
if ( xp )
{
iw . text . addTxt ( 11 , 132 ) ;
iw . text . addReplacement ( xp ) ;
cb - > sendAndApply ( & sg ) ;
}
else
{
iw . text . addTxt ( 11 , 134 ) ;
}
}
cb - > showInfoDialog ( & iw ) ;
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++)
// if((tile = IObjectInterface::cb->getTile(o->pos + offsets[i])) && tile->tertype == TerrainTile::water) //tile is in the map and is water
// 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 ) ;
TerrainTile * tile ;
2010-06-26 15:57:16 +03:00
for ( int i = 0 ; i < offsets . size ( ) ; + + i )
{
if ( tile = IObjectInterface : : cb - > getTile ( o - > pos + offsets [ i ] ) ) //tile is in the map
{
2010-07-13 08:25:40 +03:00
if ( tile - > tertype = = TerrainTile : : water & & ( ! tile - > blocked | | tile - > blockingObjects . front ( ) - > ID = = 8 ) ) //and is water and is not blocked or is blocked by boat
2010-06-26 15:57:16 +03:00
return o - > pos + offsets [ i ] ;
}
}
return int3 ( - 1 , - 1 , - 1 ) ;
2009-07-26 06:33:13 +03:00
}
2010-03-11 01:16:30 +02:00
int IBoatGenerator : : state ( ) const
2009-07-26 06:33:13 +03:00
{
int3 tile = bestLocation ( ) ;
TerrainTile * t = IObjectInterface : : cb - > getTile ( tile ) ;
if ( ! t )
2010-07-13 08:25:40 +03:00
return 2 ; //no available water
2009-07-26 06:33:13 +03:00
else if ( ! t - > blockingObjects . size ( ) )
return 0 ; //OK
else if ( t - > blockingObjects . front ( ) - > ID = = 8 )
return 1 ; //blocked with boat
else
return 2 ; //blocked
}
2010-03-11 01:16:30 +02:00
int IBoatGenerator : : getBoatType ( ) const
{
//We make good ships by default
return 1 ;
}
IBoatGenerator : : IBoatGenerator ( const CGObjectInstance * O )
: o ( O )
{
}
2010-07-13 08:25:40 +03:00
void IBoatGenerator : : getProblemText ( MetaString & out , const CGHeroInstance * visitor ) const
{
switch ( state ( ) )
{
case 1 :
out . addTxt ( MetaString : : GENERAL_TXT , 51 ) ;
break ;
case 2 :
if ( visitor )
{
out . addTxt ( MetaString : : GENERAL_TXT , 134 ) ;
out . addReplacement ( visitor - > name ) ;
}
else
out . addTxt ( MetaString : : ADVOB_TXT , 189 ) ;
break ;
case 3 :
tlog1 < < " Shipyard without water!!! " < < o - > pos < < " \t " < < o - > id < < std : : endl ;
return ;
}
}
2010-03-11 01:16:30 +02:00
void IShipyard : : getBoatCost ( std : : vector < si32 > & cost ) const
{
cost . resize ( RESOURCE_QUANTITY ) ;
cost [ 0 ] = 10 ;
cost [ 6 ] = 1000 ;
}
IShipyard : : IShipyard ( const CGObjectInstance * O )
: 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 )
return NULL ;
2009-07-26 06:33:13 +03:00
if ( obj - > ID = = TOWNI_TYPE )
{
return static_cast < CGTownInstance * > ( obj ) ;
}
else if ( obj - > ID = = 87 )
{
return static_cast < CGShipyard * > ( obj ) ;
}
else
{
2010-07-13 08:25:40 +03:00
//tlog1 << "Cannot cast to IShipyard object with ID " << obj->ID << std::endl;
2009-07-26 06:33:13 +03:00
return NULL ;
}
}
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
{
if ( tempOwner ! = h - > tempOwner )
cb - > setOwner ( id , h - > tempOwner ) ;
int s = state ( ) ;
if ( s )
{
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
{
OpenWindow ow ;
ow . id1 = id ;
ow . id2 = h - > id ;
ow . window = OpenWindow : : SHIPYARD_WINDOW ;
cb - > sendAndApply ( & ow ) ;
}
2009-08-12 05:02:58 +03:00
}
2009-08-19 09:56:53 +03:00
void CCartographer : : onHeroVisit ( const CGHeroInstance * h ) const
{
2009-08-19 13:59:42 +03:00
if ( ! hasVisited ( h - > getOwner ( ) ) ) //if hero has not visited yet this cartographer
2009-08-19 09:56:53 +03:00
{
2009-08-19 13:59:42 +03:00
if ( cb - > getResource ( h - > tempOwner , 6 ) > = 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
2009-08-19 09:56:53 +03:00
int text ;
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 ;
2009-12-30 22:49:10 +02:00
default :
2009-12-30 12:02:31 +02:00
tlog2 < < " Unrecognized subtype of cartographer " < < std : : endl ;
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 ) ;
cb - > showBlockingDialog ( & bd , boost : : bind ( & CCartographer : : buyMap , this , h , _1 ) ) ;
}
2009-08-19 13:59:42 +03:00
else //if he cannot afford
2009-08-19 09:56:53 +03:00
{
InfoWindow iw ;
iw . player = h - > getOwner ( ) ;
iw . soundID = soundBase : : CAVEHEAD ;
iw . text < < std : : pair < ui8 , ui32 > ( 11 , 28 ) ;
cb - > showInfoDialog ( & iw ) ;
}
}
2009-08-19 13:59:42 +03:00
else //if he already visited carographer
2009-08-19 09:56:53 +03:00
{
InfoWindow iw ;
iw . player = h - > getOwner ( ) ;
iw . soundID = soundBase : : CAVEHEAD ;
iw . text < < std : : pair < ui8 , ui32 > ( 11 , 24 ) ;
cb - > showInfoDialog ( & iw ) ;
}
}
2009-08-19 13:59:42 +03:00
2009-08-19 09:56:53 +03:00
void CCartographer : : buyMap ( const CGHeroInstance * h , ui32 accept ) const
{
2009-08-19 13:59:42 +03:00
if ( accept ) //if hero wants to buy map
2009-08-19 09:56:53 +03:00
{
2009-08-19 10:03:12 +03:00
cb - > giveResource ( h - > tempOwner , 6 , - 1000 ) ;
2009-08-19 09:56:53 +03:00
FoWChange fw ;
2010-07-20 12:16:48 +03:00
fw . mode = 1 ;
2009-08-19 09:56:53 +03:00
fw . player = h - > tempOwner ;
2009-11-14 22:14:15 +02:00
//subIDs of different types of cartographers:
//water = 0; land = 1; underground = 2;
cb - > getAllTiles ( fw . tiles , h - > tempOwner , subID - 1 , ! subID + 1 ) ; //reveal appropriate tiles
2009-08-19 09:56:53 +03:00
cb - > sendAndApply ( & fw ) ;
cb - > setObjProperty ( id , 10 , h - > tempOwner ) ;
}
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
{
cb - > showThievesGuildWindow ( id ) ;
2010-02-10 04:56:00 +02:00
}
void CGObelisk : : onHeroVisit ( const CGHeroInstance * h ) const
{
InfoWindow iw ;
iw . player = h - > tempOwner ;
if ( ! hasVisited ( h - > tempOwner ) )
{
iw . text . addTxt ( MetaString : : ADVOB_TXT , 96 ) ;
cb - > sendAndApply ( & iw ) ;
cb - > setObjProperty ( id , 20 , h - > tempOwner ) ; //increment general visited obelisks counter
OpenWindow ow ;
ow . id1 = h - > tempOwner ;
ow . window = OpenWindow : : PUZZLE_MAP ;
cb - > sendAndApply ( & ow ) ;
cb - > setObjProperty ( id , 10 , h - > tempOwner ) ; //mark that particular obelisk as visited
}
else
{
iw . text . addTxt ( MetaString : : ADVOB_TXT , 97 ) ;
cb - > sendAndApply ( & iw ) ;
}
}
void CGObelisk : : initObj ( )
{
obeliskCount + + ;
}
const std : : string & CGObelisk : : getHoverText ( ) const
{
hoverName = VLC - > generaltexth - > names [ ID ] ;
if ( hasVisited ( cb - > getCurrentPlayer ( ) ) )
hoverName + = " " + VLC - > generaltexth - > allTexts [ 352 ] ; //not visited
else
hoverName + = " " + VLC - > generaltexth - > allTexts [ 353 ] ; //visited
return hoverName ;
}
void CGObelisk : : setPropertyDer ( ui8 what , ui32 val )
{
CPlayersVisited : : setPropertyDer ( what , val ) ;
switch ( what )
{
case 20 :
assert ( val < PLAYER_LIMIT ) ;
visited [ val ] + + ;
2010-07-14 04:08:27 +03:00
if ( visited [ val ] > obeliskCount )
{
tlog0 < < " Error: Visited " < < visited [ val ] < < " \t \t " < < obeliskCount < < std : : endl ;
assert ( 0 ) ;
}
2010-02-10 04:56:00 +02:00
break ;
}
}
void CGLighthouse : : onHeroVisit ( const CGHeroInstance * h ) const
{
if ( h - > tempOwner ! = tempOwner )
{
ui8 oldOwner = tempOwner ;
cb - > setOwner ( id , h - > tempOwner ) ; //not ours? flag it!
InfoWindow iw ;
iw . player = h - > tempOwner ;
iw . text . addTxt ( MetaString : : ADVOB_TXT , 69 ) ;
iw . soundID = soundBase : : LIGHTHOUSE ;
cb - > sendAndApply ( & iw ) ;
giveBonusTo ( h - > tempOwner ) ;
if ( oldOwner < PLAYER_LIMIT ) //remove bonus from old owner
{
RemoveBonus rb ( RemoveBonus : : PLAYER ) ;
rb . whoID = oldOwner ;
2010-05-02 21:20:26 +03:00
rb . source = Bonus : : OBJECT ;
2010-02-10 04:56:00 +02:00
rb . id = id ;
cb - > sendAndApply ( & rb ) ;
}
}
}
void CGLighthouse : : initObj ( )
{
if ( tempOwner < PLAYER_LIMIT )
{
giveBonusTo ( tempOwner ) ;
}
}
const std : : string & CGLighthouse : : getHoverText ( ) const
{
hoverName = VLC - > generaltexth - > names [ ID ] ;
//TODO: owned by %s player
return hoverName ;
}
void CGLighthouse : : giveBonusTo ( ui8 player ) const
{
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 ;
gb . id = player ;
2010-05-02 21:20:26 +03:00
gb . bonus . duration = Bonus : : PERMANENT ;
gb . bonus . source = Bonus : : OBJECT ;
2010-02-10 04:56:00 +02:00
gb . bonus . id = id ;
cb - > sendAndApply ( & gb ) ;
2010-05-02 21:20:26 +03:00
}
void CArmedInstance : : setArmy ( const CCreatureSet & src )
{
slots . clear ( ) ;
for ( TSlots : : const_iterator i = src . Slots ( ) . begin ( ) ; i ! = src . Slots ( ) . end ( ) ; i + + )
{
CStackInstance & inserted = slots [ i - > first ] ;
inserted = i - > second ;
inserted . armyObj = this ;
}
}
CCreatureSet CArmedInstance : : getArmy ( ) const
{
return * this ;
}
void CArmedInstance : : randomizeArmy ( int type )
{
int max = VLC - > creh - > creatures . size ( ) ;
for ( TSlots : : iterator j = slots . begin ( ) ; j ! = slots . end ( ) ; j + + )
{
if ( j - > second . idRand > max )
{
if ( j - > second . idRand % 2 )
j - > second . setType ( VLC - > townh - > towns [ type ] . basicCreatures [ ( j - > second . idRand - 197 ) / 2 - 1 ] ) ;
else
j - > second . setType ( VLC - > townh - > towns [ type ] . upgradedCreatures [ ( j - > second . idRand - 197 ) / 2 - 1 ] ) ;
j - > second . idRand = - 1 ;
}
assert ( j - > second . armyObj = = this ) ;
}
return ;
}
void CArmedInstance : : getParents ( TCNodes & out , const CBonusSystemNode * root /*= NULL*/ ) const
{
const PlayerState * p = cb - > getPlayerState ( tempOwner ) ;
if ( ! p ) //occurs when initializing starting hero and heroes from the pool, also for neutral armed objects
out . insert ( & cb - > gameState ( ) - > globalEffects ) ;
else
out . insert ( p ) ; //hero always inherits bonuses from player
if ( battle )
out . insert ( battle ) ;
}
CArmedInstance : : CArmedInstance ( )
{
battle = NULL ;
}
void CArmedInstance : : getBonuses ( BonusList & out , const CSelector & selector , const CBonusSystemNode * root /*= NULL*/ ) const
{
CBonusSystemNode : : getBonuses ( out , selector , root ) ;
if ( ! battle )
{
//TODO do it clean, unify with BattleInfo version
if ( Selector : : matchesType ( selector , Bonus : : MORALE ) | | Selector : : matchesType ( selector , Bonus : : LUCK ) )
{
for ( TSlots : : const_iterator i = Slots ( ) . begin ( ) ; i ! = Slots ( ) . end ( ) ; i + + )
i - > second . getBonuses ( out , selector , Selector : : effectRange ( Bonus : : ONLY_ALLIED_ARMY ) , this ) ;
}
}
if ( Selector : : matchesType ( selector , Bonus : : MORALE ) )
{
//number of alignments and presence of undead
if ( contains ( dynamic_cast < const CStackInstance * > ( root ) ) )
{
bool archangelInArmy = false ;
bool canMix = hasBonusOfType ( Bonus : : NONEVIL_ALIGNMENT_MIX ) ;
std : : set < si8 > factions ;
for ( TSlots : : const_iterator i = Slots ( ) . begin ( ) ; i ! = Slots ( ) . end ( ) ; i + + )
{
// Take Angelic Alliance troop-mixing freedom of non-evil, non-Conflux units into account.
const si8 faction = i - > second . type - > faction ;
if ( canMix
& & ( ( faction > = 0 & & faction < = 2 ) | | faction = = 6 | | faction = = 7 ) )
{
factions . insert ( 0 ) ; // Insert a single faction of the affected group, Castle will do.
}
else
{
factions . insert ( faction ) ;
}
if ( i - > second . type - > idNumber = = 13 )
archangelInArmy = true ;
}
if ( factions . size ( ) = = 1 )
out . push_back ( Bonus ( Bonus : : PERMANENT , Bonus : : MORALE , Bonus : : ARMY , + 1 , id , VLC - > generaltexth - > arraytxt [ 115 ] ) ) ; //All troops of one alignment +1
else
{
int fcountModifier = 2 - factions . size ( ) ;
out . push_back ( Bonus ( Bonus : : PERMANENT , Bonus : : MORALE , Bonus : : ARMY , fcountModifier , id , boost : : str ( boost : : format ( VLC - > generaltexth - > arraytxt [ 114 ] ) % factions . size ( ) % fcountModifier ) ) ) ; //Troops of %d alignments %d
}
if ( vstd : : contains ( factions , 4 ) )
out . push_back ( Bonus ( Bonus : : PERMANENT , Bonus : : MORALE , Bonus : : ARMY , - 1 , id , VLC - > generaltexth - > arraytxt [ 116 ] ) ) ; //Undead in group -1
}
}
2010-05-18 10:01:54 +03:00
}
bool IMarket : : getOffer ( int id1 , int id2 , int & val1 , int & val2 , EMarketMode mode ) const
{
switch ( mode )
{
case RESOURCE_RESOURCE :
{
float effectiveness = std : : min ( ( ( float ) getMarketEfficiency ( ) + 1.0f ) / 20.0f , 0.5f ) ;
float r = VLC - > objh - > resVals [ id1 ] , //value of given resource
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
{
val1 = ( g / r ) + 0.5f ;
val2 = 1 ;
}
}
2010-05-26 12:47:53 +03:00
break ;
case CREATURE_RESOURCE :
{
const float effectivenessArray [ ] = { 0 , 0.3 , 0.45 , 0.50 , 0.65 , 0.7 , 0.85 , 0.9 , 1 } ;
float effectiveness = effectivenessArray [ std : : min ( getMarketEfficiency ( ) , 8 ) ] ;
float r = VLC - > creh - > creatures [ id1 ] - > cost [ 6 ] , //value of given creature in gold
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
{
val1 = ( g / r ) + 0.5f ;
val2 = 1 ;
}
}
break ;
case RESOURCE_PLAYER :
val1 = 1 ;
val2 = 1 ;
2010-05-18 10:01:54 +03:00
break ;
2010-06-27 19:03:01 +03:00
case RESOURCE_ARTIFACT :
{
float effectiveness = std : : min ( ( ( float ) getMarketEfficiency ( ) + 3.0f ) / 20.0f , 0.6f ) ;
float r = VLC - > objh - > resVals [ id1 ] , //value of offered resource
g = VLC - > arth - > artifacts [ id2 ] - > price / effectiveness ; //value of bought artifact in gold
if ( id1 ! = 6 ) //non-gold prices are doubled
r / = 2 ;
assert ( g > = r ) ; //should we allow artifacts cheaper than unit of resource?
val1 = ( g / r ) + 0.5f ;
val2 = 1 ;
}
break ;
2010-07-20 09:05:45 +03:00
case CREATURE_EXP :
{
val1 = 1 ;
val2 = ( VLC - > creh - > creatures [ id1 ] - > AIValue / 40 ) * 5 ;
}
break ;
2010-07-23 15:02:15 +03:00
case ARTIFACT_EXP :
{
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 ;
}
bool IMarket : : allowsTrade ( EMarketMode mode ) const
{
return false ;
}
int IMarket : : availableUnits ( EMarketMode mode , int marketItemSerial ) const
{
2010-05-26 12:47:53 +03:00
switch ( mode )
{
case RESOURCE_RESOURCE :
case ARTIFACT_RESOURCE :
case CREATURE_RESOURCE :
return - 1 ;
default :
return 1 ;
}
2010-05-18 10:01:54 +03:00
}
std : : vector < int > IMarket : : availableItemsIds ( EMarketMode mode ) const
{
std : : vector < int > ret ;
2010-05-26 12:47:53 +03:00
switch ( mode )
{
case RESOURCE_RESOURCE :
case ARTIFACT_RESOURCE :
case CREATURE_RESOURCE :
2010-05-18 10:01:54 +03:00
for ( int i = 0 ; i < 7 ; i + + )
ret . push_back ( i ) ;
2010-05-26 12:47:53 +03:00
break ;
}
2010-05-18 10:01:54 +03:00
return ret ;
}
const IMarket * IMarket : : castFrom ( const CGObjectInstance * obj )
{
switch ( obj - > ID )
{
case TOWNI_TYPE :
return static_cast < const CGTownInstance * > ( obj ) ;
2010-07-06 05:10:26 +03:00
case 2 : //Altar of Sacrifice
2010-05-26 12:47:53 +03:00
case 7 : //Black Market
2010-05-18 10:01:54 +03:00
case 99 : //Trading Post
case 221 : //Trading Post (snow)
2010-05-26 12:47:53 +03:00
case 213 : //Freelancer's Guild
2010-05-18 10:01:54 +03:00
return static_cast < const CGMarket * > ( obj ) ;
2010-07-20 17:08:13 +03:00
case 104 : //University
return static_cast < const CGUniversity * > ( obj ) ;
2010-05-18 10:01:54 +03:00
default :
tlog1 < < " Cannot cast to IMarket object with ID " < < obj - > ID < < std : : endl ;
return NULL ;
}
}
IMarket : : IMarket ( const CGObjectInstance * O )
: o ( O )
{
}
std : : vector < EMarketMode > IMarket : : availableModes ( ) const
{
std : : vector < EMarketMode > ret ;
for ( int i = 0 ; i < MARTKET_AFTER_LAST_PLACEHOLDER ; i + + )
if ( allowsTrade ( ( EMarketMode ) i ) )
ret . push_back ( ( EMarketMode ) i ) ;
return ret ;
}
void CGMarket : : onHeroVisit ( const CGHeroInstance * h ) const
{
OpenWindow ow ;
ow . id1 = id ;
ow . id2 = h - > id ;
ow . window = OpenWindow : : MARKET_WINDOW ;
cb - > sendAndApply ( & ow ) ;
}
int CGMarket : : getMarketEfficiency ( ) const
{
return 5 ;
}
bool CGMarket : : allowsTrade ( EMarketMode mode ) const
{
switch ( mode )
{
case RESOURCE_RESOURCE :
case RESOURCE_PLAYER :
switch ( ID )
{
case 99 : //Trading Post
case 221 : //Trading Post (snow)
return true ;
default :
return false ;
}
2010-05-26 12:47:53 +03:00
case CREATURE_RESOURCE :
return ID = = 213 ; //Freelancer's Guild
2010-07-26 18:37:58 +03:00
//case ARTIFACT_RESOURCE:
2010-06-27 19:03:01 +03:00
case RESOURCE_ARTIFACT :
return ID = = 7 ; //Black Market
2010-07-06 05:10:26 +03:00
case ARTIFACT_EXP :
case CREATURE_EXP :
return ID = = 2 ; //TODO? check here for alignment of visiting hero? - would not be coherent with other checks here
2010-07-20 17:08:13 +03:00
case RESOURCE_SKILL :
return ID = = 104 ; //University
2010-05-18 10:01:54 +03:00
}
2010-05-26 12:47:53 +03:00
return false ;
2010-05-18 10:01:54 +03:00
}
int CGMarket : : availableUnits ( EMarketMode mode , int marketItemSerial ) const
{
return - 1 ;
}
std : : vector < int > CGMarket : : availableItemsIds ( EMarketMode mode ) const
{
switch ( mode )
{
case RESOURCE_RESOURCE :
case RESOURCE_PLAYER :
return IMarket : : availableItemsIds ( mode ) ;
default :
return std : : vector < int > ( ) ;
}
}
CGMarket : : CGMarket ( )
: IMarket ( this )
{
2010-06-26 19:02:10 +03:00
}
std : : vector < int > CGBlackMarket : : availableItemsIds ( EMarketMode mode ) const
{
switch ( mode )
{
case ARTIFACT_RESOURCE :
return IMarket : : availableItemsIds ( mode ) ;
case RESOURCE_ARTIFACT :
{
std : : vector < int > ret ;
BOOST_FOREACH ( const CArtifact * a , artifacts )
if ( a )
ret . push_back ( a - > id ) ;
else
ret . push_back ( - 1 ) ;
return ret ;
}
default :
return std : : vector < int > ( ) ;
}
}
void CGBlackMarket : : newTurn ( ) const
{
2010-06-27 19:03:01 +03:00
if ( cb - > getDate ( 2 ) ! = 1 )
return ;
2010-06-26 19:02:10 +03:00
2010-06-27 19:03:01 +03:00
SetAvailableArtifacts saa ;
saa . id = id ;
cb - > pickAllowedArtsSet ( saa . arts ) ;
cb - > sendAndApply ( & saa ) ;
2010-07-20 17:08:13 +03:00
}
void CGUniversity : : initObj ( )
{
std : : vector < int > toChoose ;
for ( int i = 0 ; i < SKILL_QUANTITY ; i + + )
if ( cb - > isAllowed ( 2 , i ) )
toChoose . push_back ( i ) ;
if ( toChoose . size ( ) < 4 )
{
tlog0 < < " Warning: less then 4 available skills was found by University initializer! \n " ;
return ;
}
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
}
}
std : : vector < int > CGUniversity : : availableItemsIds ( EMarketMode mode ) const
{
switch ( mode )
{
case RESOURCE_SKILL :
return skills ;
default :
return std : : vector < int > ( ) ;
}
}
void CGUniversity : : onHeroVisit ( const CGHeroInstance * h ) const
{
OpenWindow ow ;
ow . id1 = id ;
ow . id2 = h - > id ;
ow . window = OpenWindow : : UNIVERSITY_WINDOW ;
cb - > sendAndApply ( & ow ) ;
}