2011-12-14 00:23:17 +03:00
# include "StdInc.h"
2008-02-25 01:06:27 +02:00
# include "CGameState.h"
2011-12-14 00:23:17 +03:00
2008-06-30 03:06:41 +03:00
# include <boost/random/linear_congruential.hpp>
2011-12-14 00:23:17 +03:00
# include "CCampaignHandler.h"
2010-12-20 23:22:53 +02:00
# include "CDefObjInfoHandler.h"
# include "CArtHandler.h"
# include "CBuildingHandler.h"
# include "CGeneralTextHandler.h"
# include "CTownHandler.h"
# include "CSpellHandler.h"
# include "CHeroHandler.h"
# include "CObjectHandler.h"
# include "CCreatureHandler.h"
2009-05-20 13:08:56 +03:00
# include "VCMI_Lib.h"
# include "Connection.h"
2008-06-30 03:06:41 +03:00
# include "map.h"
2011-12-14 00:23:17 +03:00
# include "StartInfo.h"
2009-05-20 13:08:56 +03:00
# include "NetPacks.h"
2011-12-14 00:23:17 +03:00
# include "RegisterTypes.h"
2010-10-24 14:35:14 +03:00
# include "CMapInfo.h"
2010-12-25 21:23:30 +02:00
# include "BattleState.h"
2011-08-20 05:53:57 +03:00
# include "../lib/JsonNode.h"
2011-12-14 00:23:17 +03:00
# include "GameConstants.h"
2009-07-09 22:15:22 +03:00
2012-03-27 23:08:54 +03:00
DLL_LINKAGE boost : : rand48 ran ;
2010-06-07 08:28:12 +03:00
class CGObjectInstance ;
2008-02-25 01:06:27 +02:00
2008-09-07 06:38:37 +03:00
# ifdef min
# undef min
# endif
# ifdef max
# undef max
# endif
2008-08-20 09:57:53 +03:00
2009-04-15 17:03:31 +03:00
/*
* CGameState . 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
*
*/
2009-03-15 14:53:58 +02:00
void foofoofoo ( )
{
//never called function to force instantation of templates
int * ccc = NULL ;
registerTypes ( ( CISer < CConnection > & ) * ccc ) ;
registerTypes ( ( COSer < CConnection > & ) * ccc ) ;
registerTypes ( ( CSaveFile & ) * ccc ) ;
registerTypes ( ( CLoadFile & ) * ccc ) ;
registerTypes ( ( CTypeList & ) * ccc ) ;
}
2010-09-04 17:47:39 +03:00
template < typename T > class CApplyOnGS ;
2009-03-15 14:53:58 +02:00
2009-03-07 00:25:19 +02:00
class CBaseForGSApply
{
public :
2012-02-16 20:10:58 +03:00
virtual void applyOnGS ( CGameState * gs , void * pack ) const = 0 ;
2010-01-02 03:48:44 +02:00
virtual ~ CBaseForGSApply ( ) { } ;
2010-09-03 21:42:54 +03:00
template < typename U > static CBaseForGSApply * getApplier ( const U * t = NULL )
{
return new CApplyOnGS < U > ;
}
2009-03-07 00:25:19 +02:00
} ;
2010-09-03 21:42:54 +03:00
2009-03-07 00:25:19 +02:00
template < typename T > class CApplyOnGS : public CBaseForGSApply
{
public :
void applyOnGS ( CGameState * gs , void * pack ) const
{
T * ptr = static_cast < T * > ( pack ) ;
2012-02-20 00:03:43 +03:00
boost : : unique_lock < boost : : shared_mutex > lock ( * gs - > mx ) ;
2009-03-07 00:25:19 +02:00
ptr - > applyGs ( gs ) ;
}
} ;
2010-09-04 17:47:39 +03:00
static CApplier < CBaseForGSApply > * applierGs = NULL ;
2009-03-07 00:25:19 +02:00
2009-09-07 05:29:44 +03:00
class IObjectCaller
{
public :
2012-04-08 13:34:23 +03:00
virtual ~ IObjectCaller ( ) { } ;
2009-09-07 05:29:44 +03:00
virtual void preInit ( ) = 0 ;
virtual void postInit ( ) = 0 ;
} ;
template < typename T >
class CObjectCaller : public IObjectCaller
{
public :
void preInit ( )
{
2010-07-12 13:20:25 +03:00
//T::preInit();
2009-09-07 05:29:44 +03:00
}
void postInit ( )
{
2010-07-12 13:20:25 +03:00
//T::postInit();
2009-09-07 05:29:44 +03:00
}
} ;
class CObjectCallersHandler
{
public :
2012-02-16 20:10:58 +03:00
std : : vector < IObjectCaller * > apps ;
2009-09-07 05:29:44 +03:00
template < typename T > void registerType ( const T * t = NULL )
{
apps . push_back ( new CObjectCaller < T > ) ;
}
CObjectCallersHandler ( )
{
registerTypes1 ( * this ) ;
}
~ CObjectCallersHandler ( )
{
for ( size_t i = 0 ; i < apps . size ( ) ; i + + )
delete apps [ i ] ;
}
void preInit ( )
{
2010-07-12 13:20:25 +03:00
// for (size_t i = 0; i < apps.size(); i++)
// apps[i]->preInit();
2009-09-07 05:29:44 +03:00
}
void postInit ( )
{
2010-08-20 19:23:43 +03:00
//for (size_t i = 0; i < apps.size(); i++)
//apps[i]->postInit();
2009-09-07 05:29:44 +03:00
}
} * objCaller = NULL ;
2009-07-09 22:15:22 +03:00
void MetaString : : getLocalString ( const std : : pair < ui8 , ui32 > & txt , std : : string & dst ) const
2008-12-27 03:01:59 +02:00
{
2009-07-09 22:15:22 +03:00
int type = txt . first , ser = txt . second ;
if ( type = = ART_NAMES )
{
2010-06-26 19:02:10 +03:00
dst = VLC - > arth - > artifacts [ ser ] - > Name ( ) ;
2009-07-09 22:15:22 +03:00
}
else if ( type = = CRE_PL_NAMES )
{
2010-05-02 21:20:26 +03:00
dst = VLC - > creh - > creatures [ ser ] - > namePl ;
2009-07-09 22:15:22 +03:00
}
else if ( type = = MINE_NAMES )
{
dst = VLC - > generaltexth - > mines [ ser ] . first ;
}
else if ( type = = MINE_EVNTS )
{
dst = VLC - > generaltexth - > mines [ ser ] . second ;
}
else if ( type = = SPELL_NAME )
{
2010-12-19 16:39:56 +02:00
dst = VLC - > spellh - > spells [ ser ] - > name ;
2009-07-09 22:15:22 +03:00
}
else if ( type = = CRE_SING_NAMES )
{
2010-05-02 21:20:26 +03:00
dst = VLC - > creh - > creatures [ ser ] - > nameSing ;
2009-07-09 22:15:22 +03:00
}
2010-03-01 20:22:22 +02:00
else if ( type = = ART_DESCR )
{
2010-06-26 19:02:10 +03:00
dst = VLC - > arth - > artifacts [ ser ] - > Description ( ) ;
2010-03-01 20:22:22 +02:00
}
2009-07-09 22:15:22 +03:00
else
2008-12-27 03:01:59 +02:00
{
2009-07-09 22:15:22 +03:00
std : : vector < std : : string > * vec ;
switch ( type )
2008-12-27 03:01:59 +02:00
{
2009-07-09 22:15:22 +03:00
case GENERAL_TXT :
vec = & VLC - > generaltexth - > allTexts ;
break ;
case XTRAINFO_TXT :
vec = & VLC - > generaltexth - > xtrainfo ;
break ;
case OBJ_NAMES :
vec = & VLC - > generaltexth - > names ;
break ;
case RES_NAMES :
vec = & VLC - > generaltexth - > restypes ;
break ;
case ARRAY_TXT :
vec = & VLC - > generaltexth - > arraytxt ;
break ;
case CREGENS :
vec = & VLC - > generaltexth - > creGens ;
break ;
2009-07-26 13:43:22 +03:00
case CREGENS4 :
vec = & VLC - > generaltexth - > creGens4 ;
break ;
2009-07-09 22:15:22 +03:00
case ADVOB_TXT :
vec = & VLC - > generaltexth - > advobtxt ;
break ;
case ART_EVNTS :
vec = & VLC - > generaltexth - > artifEvents ;
break ;
case SEC_SKILL_NAME :
vec = & VLC - > generaltexth - > skillName ;
break ;
2010-02-02 01:30:03 +02:00
case COLOR :
vec = & VLC - > generaltexth - > capColors ;
break ;
2011-05-28 04:02:28 +03:00
default :
tlog1 < < " Failed string substitution because type is " < < type < < std : : endl ;
dst = " #@# " ;
return ;
2008-12-27 03:01:59 +02:00
}
2011-05-28 04:02:28 +03:00
if ( vec - > size ( ) < = ser )
{
tlog1 < < " Failed string substitution with type " < < type < < " because index " < < ser < < " is out of bounds! \n " ;
dst = " #!# " ;
}
else
dst = ( * vec ) [ ser ] ;
2009-07-09 22:15:22 +03:00
}
}
2011-12-14 00:23:17 +03:00
DLL_LINKAGE void MetaString : : toString ( std : : string & dst ) const
2009-07-09 22:15:22 +03:00
{
size_t exSt = 0 , loSt = 0 , nums = 0 ;
dst . clear ( ) ;
for ( size_t i = 0 ; i < message . size ( ) ; + + i )
{ //TEXACT_STRING, TLOCAL_STRING, TNUMBER, TREPLACE_ESTRING, TREPLACE_LSTRING, TREPLACE_NUMBER
switch ( message [ i ] )
2008-12-27 03:01:59 +02:00
{
2009-07-09 22:15:22 +03:00
case TEXACT_STRING :
dst + = exactStrings [ exSt + + ] ;
break ;
case TLOCAL_STRING :
2008-12-27 03:01:59 +02:00
{
2009-07-09 22:15:22 +03:00
std : : string hlp ;
getLocalString ( localStrings [ loSt + + ] , hlp ) ;
dst + = hlp ;
2008-12-27 03:01:59 +02:00
}
2009-07-09 22:15:22 +03:00
break ;
case TNUMBER :
dst + = boost : : lexical_cast < std : : string > ( numbers [ nums + + ] ) ;
break ;
case TREPLACE_ESTRING :
2009-09-16 19:16:57 +03:00
dst . replace ( dst . find ( " %s " ) , 2 , exactStrings [ exSt + + ] ) ;
2009-07-09 22:15:22 +03:00
break ;
case TREPLACE_LSTRING :
2008-12-27 03:01:59 +02:00
{
2009-07-09 22:15:22 +03:00
std : : string hlp ;
getLocalString ( localStrings [ loSt + + ] , hlp ) ;
2009-09-16 19:16:57 +03:00
dst . replace ( dst . find ( " %s " ) , 2 , hlp ) ;
2008-12-27 03:01:59 +02:00
}
2009-07-09 22:15:22 +03:00
break ;
case TREPLACE_NUMBER :
2009-09-16 19:16:57 +03:00
dst . replace ( dst . find ( " %d " ) , 2 , boost : : lexical_cast < std : : string > ( numbers [ nums + + ] ) ) ;
2009-07-09 22:15:22 +03:00
break ;
2010-08-26 10:23:08 +03:00
case TREPLACE_PLUSNUMBER :
dst . replace ( dst . find ( " %+d " ) , 3 , ' + ' + boost : : lexical_cast < std : : string > ( numbers [ nums + + ] ) ) ;
break ;
2009-07-09 22:15:22 +03:00
default :
tlog1 < < " MetaString processing error! \n " ;
break ;
2008-12-27 03:01:59 +02:00
}
}
}
2008-10-26 22:58:34 +02:00
2011-12-14 00:23:17 +03:00
DLL_LINKAGE std : : string MetaString : : toString ( ) const
2010-07-13 08:25:40 +03:00
{
std : : string ret ;
toString ( ret ) ;
return ret ;
}
2011-12-14 00:23:17 +03:00
DLL_LINKAGE std : : string MetaString : : buildList ( ) const
2009-09-16 19:16:57 +03:00
///used to handle loot from creature bank
{
size_t exSt = 0 , loSt = 0 , nums = 0 ;
2012-02-16 20:10:58 +03:00
std : : string lista ;
2009-09-16 19:16:57 +03:00
for ( int i = 0 ; i < message . size ( ) ; + + i )
{
2011-05-30 22:20:14 +03:00
if ( i > 0 & & ( message [ i ] = = TEXACT_STRING | | message [ i ] = = TLOCAL_STRING ) )
2009-09-16 19:16:57 +03:00
{
2009-09-17 22:22:47 +03:00
if ( exSt = = exactStrings . size ( ) - 1 )
lista + = VLC - > generaltexth - > allTexts [ 141 ] ; //" and "
2009-09-16 19:16:57 +03:00
else
lista + = " , " ;
}
switch ( message [ i ] )
{
case TEXACT_STRING :
lista + = exactStrings [ exSt + + ] ;
break ;
case TLOCAL_STRING :
{
std : : string hlp ;
getLocalString ( localStrings [ loSt + + ] , hlp ) ;
lista + = hlp ;
}
break ;
case TNUMBER :
lista + = boost : : lexical_cast < std : : string > ( numbers [ nums + + ] ) ;
break ;
case TREPLACE_ESTRING :
lista . replace ( lista . find ( " %s " ) , 2 , exactStrings [ exSt + + ] ) ;
break ;
case TREPLACE_LSTRING :
{
std : : string hlp ;
getLocalString ( localStrings [ loSt + + ] , hlp ) ;
lista . replace ( lista . find ( " %s " ) , 2 , hlp ) ;
}
break ;
case TREPLACE_NUMBER :
lista . replace ( lista . find ( " %d " ) , 2 , boost : : lexical_cast < std : : string > ( numbers [ nums + + ] ) ) ;
break ;
default :
tlog1 < < " MetaString processing error! \n " ;
}
}
return lista ;
}
2010-11-22 02:34:46 +02:00
void MetaString : : addCreReplacement ( TCreature id , TQuantity count ) //adds sing or plural name;
{
assert ( count ) ;
if ( count = = 1 )
addReplacement ( CRE_SING_NAMES , id ) ;
else
addReplacement ( CRE_PL_NAMES , id ) ;
}
void MetaString : : addReplacement ( const CStackBasicDescriptor & stack )
2010-04-02 05:07:40 +03:00
{
assert ( stack . count ) ; //valid count
assert ( stack . type ) ; //valid type
2011-02-11 14:27:38 +02:00
addCreReplacement ( stack . type - > idNumber , stack . count ) ;
2010-04-02 05:07:40 +03:00
}
2009-05-24 01:57:39 +03:00
static CGObjectInstance * createObject ( int id , int subid , int3 pos , int owner )
2008-07-27 20:07:37 +03:00
{
CGObjectInstance * nobj ;
switch ( id )
{
2011-12-14 00:23:17 +03:00
case GameConstants : : HEROI_TYPE : //hero
2008-07-27 20:07:37 +03:00
{
2008-10-26 22:58:34 +02:00
CGHeroInstance * nobj = new CGHeroInstance ( ) ;
2008-07-27 20:07:37 +03:00
nobj - > pos = pos ;
nobj - > tempOwner = owner ;
nobj - > subID = subid ;
2008-10-26 22:58:34 +02:00
//nobj->initHero(ran);
2008-07-27 20:07:37 +03:00
return nobj ;
}
2011-12-14 00:23:17 +03:00
case GameConstants : : TOWNI_TYPE : //town
2008-07-27 20:07:37 +03:00
nobj = new CGTownInstance ;
break ;
default : //rest of objects
nobj = new CGObjectInstance ;
nobj - > defInfo = VLC - > dobjinfo - > gobjs [ id ] [ subid ] ;
break ;
}
nobj - > ID = id ;
nobj - > subID = subid ;
if ( ! nobj - > defInfo )
2008-09-19 15:09:15 +03:00
tlog3 < < " No def declaration for " < < id < < " " < < subid < < std : : endl ;
2008-07-27 20:07:37 +03:00
nobj - > pos = pos ;
//nobj->state = NULL;//new CLuaObjectScript();
nobj - > tempOwner = owner ;
nobj - > defInfo - > id = id ;
nobj - > defInfo - > subid = subid ;
//assigning defhandler
2011-12-14 00:23:17 +03:00
if ( nobj - > ID = = GameConstants : : HEROI_TYPE | | nobj - > ID = = GameConstants : : TOWNI_TYPE )
2008-07-27 20:07:37 +03:00
return nobj ;
nobj - > defInfo = VLC - > dobjinfo - > gobjs [ id ] [ subid ] ;
return nobj ;
}
2009-09-02 17:10:19 +03:00
2010-12-20 15:04:24 +02:00
CGHeroInstance * CGameState : : HeroesPool : : pickHeroFor ( bool native , int player , const CTown * town , bmap < ui32 , ConstTransitivePtr < CGHeroInstance > > & available , const CHeroClass * bannedClass /*= NULL*/ ) const
2008-11-01 00:41:22 +02:00
{
2009-08-05 03:05:37 +03:00
CGHeroInstance * ret = NULL ;
2011-12-14 00:23:17 +03:00
if ( player < 0 | | player > = GameConstants : : PLAYER_LIMIT )
2008-11-01 00:41:22 +02:00
{
2008-12-22 19:48:41 +02:00
tlog1 < < " Cannot pick hero for " < < town - > Name ( ) < < " . Wrong owner! \n " ;
2008-11-01 00:41:22 +02:00
return NULL ;
}
2009-08-05 03:05:37 +03:00
2008-11-01 00:41:22 +02:00
std : : vector < CGHeroInstance * > pool ;
2009-08-05 03:05:37 +03:00
2008-11-01 00:41:22 +02:00
if ( native )
{
2010-12-20 15:04:24 +02:00
for ( bmap < ui32 , ConstTransitivePtr < CGHeroInstance > > : : iterator i = available . begin ( ) ; i ! = available . end ( ) ; i + + )
2008-11-01 00:41:22 +02:00
{
2009-08-05 03:05:37 +03:00
if ( pavailable . find ( i - > first ) - > second & 1 < < player
& & i - > second - > type - > heroType / 2 = = town - > typeID )
2008-11-01 00:41:22 +02:00
{
2011-09-24 04:15:36 +03:00
pool . push_back ( i - > second ) ; //get all available heroes
2008-11-01 00:41:22 +02:00
}
}
if ( ! pool . size ( ) )
2009-08-05 03:05:37 +03:00
{
tlog1 < < " Cannot pick native hero for " < < player < < " . Picking any... \n " ;
return pickHeroFor ( false , player , town , available ) ;
}
2008-11-01 00:41:22 +02:00
else
2009-08-05 03:05:37 +03:00
{
ret = pool [ rand ( ) % pool . size ( ) ] ;
}
2008-11-01 00:41:22 +02:00
}
else
{
2009-08-05 03:05:37 +03:00
int sum = 0 , r ;
2010-12-20 15:04:24 +02:00
for ( bmap < ui32 , ConstTransitivePtr < CGHeroInstance > > : : iterator i = available . begin ( ) ; i ! = available . end ( ) ; i + + )
2008-11-01 00:41:22 +02:00
{
2011-05-30 22:20:14 +03:00
if ( ( ! bannedClass & & ( pavailable . find ( i - > first ) - > second & ( 1 < < player ) ) ) | |
i - > second - > type - > heroClass ! = bannedClass )
2008-11-01 00:41:22 +02:00
{
pool . push_back ( i - > second ) ;
2009-11-15 16:06:25 +02:00
sum + = i - > second - > type - > heroClass - > selectionProbability [ town - > typeID ] ; //total weight
2008-11-01 00:41:22 +02:00
}
}
if ( ! pool . size ( ) )
{
tlog1 < < " There are no heroes available for player " < < player < < " ! \n " ;
return NULL ;
}
2009-08-05 03:05:37 +03:00
2008-11-01 00:41:22 +02:00
r = rand ( ) % sum ;
2011-12-14 00:23:17 +03:00
for ( ui32 i = 0 ; i < pool . size ( ) ; i + + )
2008-11-01 00:41:22 +02:00
{
r - = pool [ i ] - > type - > heroClass - > selectionProbability [ town - > typeID ] ;
2009-11-15 16:06:25 +02:00
if ( r < 0 )
{
2009-08-05 03:05:37 +03:00
ret = pool [ i ] ;
2009-11-15 16:06:25 +02:00
break ;
}
2008-11-01 00:41:22 +02:00
}
2009-08-05 03:05:37 +03:00
if ( ! ret )
ret = pool . back ( ) ;
2008-11-01 00:41:22 +02:00
}
2009-08-05 03:05:37 +03:00
available . erase ( ret - > subID ) ;
return ret ;
2008-11-01 00:41:22 +02:00
}
2009-08-05 03:05:37 +03:00
2009-03-07 00:11:17 +02:00
//void CGameState::apply(CPack * pack)
//{
// while(!mx->try_lock())
// boost::this_thread::sleep(boost::posix_time::milliseconds(50)); //give other threads time to finish
// //applyNL(pack);
// mx->unlock();
//}
2008-06-30 03:06:41 +03:00
int CGameState : : pickHero ( int owner )
{
int h = - 1 ;
2010-10-24 14:35:14 +03:00
const PlayerSettings & ps = scenarioOps - > getIthPlayersSettings ( owner ) ;
if ( ! map - > getHero ( h = ps . hero , 0 ) & & h > = 0 ) //we haven't used selected hero
2008-06-30 03:06:41 +03:00
return h ;
int i = 0 ;
2010-10-31 00:53:41 +03:00
2008-06-30 03:06:41 +03:00
do //try to find free hero of our faction
{
i + + ;
2011-12-14 00:23:17 +03:00
h = ps . castle * GameConstants : : HEROES_PER_TYPE * 2 + ( ran ( ) % ( GameConstants : : HEROES_PER_TYPE * 2 ) ) ; //->scenarioOps->playerInfos[pru].hero = VLC->
2008-06-30 03:06:41 +03:00
} while ( map - > getHero ( h ) & & i < 175 ) ;
if ( i > 174 ) //probably no free heroes - there's no point in further search, we'll take first free
{
2008-09-19 15:09:15 +03:00
tlog3 < < " Warning: cannot find free hero - trying to get first available... " < < std : : endl ;
2011-12-14 00:23:17 +03:00
for ( int j = 0 ; j < GameConstants : : HEROES_PER_TYPE * 2 * GameConstants : : F_NUMBER ; j + + )
2008-06-30 03:06:41 +03:00
if ( ! map - > getHero ( j ) )
h = j ;
}
return h ;
}
2010-07-09 02:03:27 +03:00
2010-01-29 22:52:45 +02:00
2009-10-26 11:11:10 +02:00
std : : pair < int , int > CGameState : : pickObject ( CGObjectInstance * obj )
2008-02-25 01:06:27 +02:00
{
2008-06-30 03:06:41 +03:00
switch ( obj - > ID )
{
2010-07-09 08:07:56 +03:00
case 65 :
2010-06-28 08:07:21 +03:00
return std : : pair < int , int > ( 5 , VLC - > arth - > getRandomArt ( CArtifact : : ART_TREASURE | CArtifact : : ART_MINOR | CArtifact : : ART_MAJOR | CArtifact : : ART_RELIC ) ) ;
2009-10-26 11:11:10 +02:00
case 66 : //random treasure artifact
2010-06-28 08:07:21 +03:00
return std : : pair < int , int > ( 5 , VLC - > arth - > getRandomArt ( CArtifact : : ART_TREASURE ) ) ;
2009-10-26 11:11:10 +02:00
case 67 : //random minor artifact
2010-06-28 08:07:21 +03:00
return std : : pair < int , int > ( 5 , VLC - > arth - > getRandomArt ( CArtifact : : ART_MINOR ) ) ;
2009-10-26 11:11:10 +02:00
case 68 : //random major artifact
2010-06-28 08:07:21 +03:00
return std : : pair < int , int > ( 5 , VLC - > arth - > getRandomArt ( CArtifact : : ART_MAJOR ) ) ;
2009-10-26 11:11:10 +02:00
case 69 : //random relic artifact
2010-06-28 08:07:21 +03:00
return std : : pair < int , int > ( 5 , VLC - > arth - > getRandomArt ( CArtifact : : ART_RELIC ) ) ;
2008-06-30 03:06:41 +03:00
case 70 : //random hero
2011-12-14 00:23:17 +03:00
return std : : pair < int , int > ( GameConstants : : HEROI_TYPE , pickHero ( obj - > tempOwner ) ) ;
2008-06-30 03:06:41 +03:00
case 71 : //random monster
2012-02-16 20:10:58 +03:00
return std : : pair < int , int > ( 54 , VLC - > creh - > pickRandomMonster ( boost : : ref ( ran ) ) ) ;
2008-06-30 03:06:41 +03:00
case 72 : //random monster lvl1
2012-02-16 20:10:58 +03:00
return std : : pair < int , int > ( 54 , VLC - > creh - > pickRandomMonster ( boost : : ref ( ran ) , 1 ) ) ;
2008-06-30 03:06:41 +03:00
case 73 : //random monster lvl2
2011-02-10 15:12:53 +02:00
return std : : pair < int , int > ( 54 , VLC - > creh - > pickRandomMonster ( boost : : ref ( ran ) , 2 ) ) ;
2008-06-30 03:06:41 +03:00
case 74 : //random monster lvl3
2011-02-10 15:12:53 +02:00
return std : : pair < int , int > ( 54 , VLC - > creh - > pickRandomMonster ( boost : : ref ( ran ) , 3 ) ) ;
2008-06-30 03:06:41 +03:00
case 75 : //random monster lvl4
2011-02-10 15:12:53 +02:00
return std : : pair < int , int > ( 54 , VLC - > creh - > pickRandomMonster ( boost : : ref ( ran ) , 4 ) ) ;
2008-06-30 03:06:41 +03:00
case 76 : //random resource
2012-02-16 20:10:58 +03:00
return std : : pair < int , int > ( 79 , ran ( ) % 7 ) ; //now it's OH3 style, use %8 for mithril
2008-06-30 03:06:41 +03:00
case 77 : //random town
{
2009-05-01 17:37:25 +03:00
int align = ( static_cast < CGTownInstance * > ( obj ) ) - > alignment ,
2008-06-30 03:06:41 +03:00
f ;
2011-12-14 00:23:17 +03:00
if ( align > GameConstants : : PLAYER_LIMIT - 1 ) //same as owner / random
2008-06-30 03:06:41 +03:00
{
2011-12-14 00:23:17 +03:00
if ( obj - > tempOwner > GameConstants : : PLAYER_LIMIT - 1 )
2008-06-30 03:06:41 +03:00
f = - 1 ; //random
else
f = scenarioOps - > getIthPlayersSettings ( obj - > tempOwner ) . castle ;
}
else
{
f = scenarioOps - > getIthPlayersSettings ( align ) . castle ;
}
if ( f < 0 ) f = ran ( ) % VLC - > townh - > towns . size ( ) ;
2012-02-16 20:10:58 +03:00
return std : : pair < int , int > ( GameConstants : : TOWNI_TYPE , f ) ;
2008-06-30 03:06:41 +03:00
}
case 162 : //random monster lvl5
2011-02-10 15:12:53 +02:00
return std : : pair < int , int > ( 54 , VLC - > creh - > pickRandomMonster ( boost : : ref ( ran ) , 5 ) ) ;
2008-06-30 03:06:41 +03:00
case 163 : //random monster lvl6
2011-02-10 15:12:53 +02:00
return std : : pair < int , int > ( 54 , VLC - > creh - > pickRandomMonster ( boost : : ref ( ran ) , 6 ) ) ;
2008-06-30 03:06:41 +03:00
case 164 : //random monster lvl7
2011-02-10 15:12:53 +02:00
return std : : pair < int , int > ( 54 , VLC - > creh - > pickRandomMonster ( boost : : ref ( ran ) , 7 ) ) ;
2012-05-11 22:03:40 +03:00
case 216 : //random dwellings
case 217 :
case 218 :
2008-06-30 03:06:41 +03:00
{
2010-02-21 20:07:24 +02:00
CGDwelling * dwl = static_cast < CGDwelling * > ( obj ) ;
2012-05-11 22:03:40 +03:00
int faction ;
//if castle alignment available
if ( auto info = dynamic_cast < CCreGenAsCastleInfo * > ( dwl - > info ) )
2008-06-30 03:06:41 +03:00
{
2012-05-11 22:03:40 +03:00
faction = ran ( ) % GameConstants : : F_NUMBER ;
if ( info - > asCastle )
2008-06-30 03:06:41 +03:00
{
2012-05-11 22:03:40 +03:00
for ( ui32 i = 0 ; i < map - > objects . size ( ) ; i + + )
2008-06-30 03:06:41 +03:00
{
2012-05-11 22:03:40 +03:00
if ( map - > objects [ i ] - > ID = = 77 & & dynamic_cast < CGTownInstance * > ( map - > objects [ i ] . get ( ) ) - > identifier = = info - > identifier )
{
randomizeObject ( map - > objects [ i ] ) ; //we have to randomize the castle first
faction = map - > objects [ i ] - > subID ;
break ;
}
else if ( map - > objects [ i ] - > ID = = GameConstants : : TOWNI_TYPE & & dynamic_cast < CGTownInstance * > ( map - > objects [ i ] . get ( ) ) - > identifier = = info - > identifier )
{
faction = map - > objects [ i ] - > subID ;
break ;
}
2008-06-30 03:06:41 +03:00
}
}
2012-05-11 22:03:40 +03:00
else
2008-06-30 03:06:41 +03:00
{
2012-05-11 22:03:40 +03:00
while ( ( ! ( info - > castles [ 0 ] & ( 1 < < faction ) ) ) )
2008-06-30 03:06:41 +03:00
{
2012-05-11 22:03:40 +03:00
if ( ( faction > 7 ) & & ( info - > castles [ 1 ] & ( 1 < < ( faction - 8 ) ) ) )
break ;
faction = ran ( ) % GameConstants : : F_NUMBER ;
2008-06-30 03:06:41 +03:00
}
}
}
2012-05-11 22:03:40 +03:00
else // castle alignment fixed
faction = obj - > subID ;
int level ;
//if level set to range
if ( auto info = dynamic_cast < CCreGenLeveledInfo * > ( dwl - > info ) )
level = ( ( info - > maxLevel - info - > minLevel ) ? ( ran ( ) % ( info - > maxLevel - info - > minLevel ) + info - > minLevel ) : ( info - > minLevel ) ) ;
else // fixed level
level = obj - > subID ;
2010-02-21 20:07:24 +02:00
delete dwl - > info ;
2012-05-11 22:03:40 +03:00
dwl - > info = nullptr ;
std : : pair < int , int > result ( - 1 , - 1 ) ;
int cid = VLC - > townh - > towns [ faction ] . basicCreatures [ level ] ;
2012-06-01 14:35:31 +03:00
//golem factory is not in list of cregens but can be placed as random object
static const int factoryCreatures [ ] = { 32 , 33 , 116 , 117 } ;
std : : vector < int > factory ( std : : begin ( factoryCreatures ) , std : : end ( factoryCreatures ) ) ;
if ( vstd : : contains ( factory , cid ) )
result = std : : pair < int , int > ( 20 , 1 ) ;
2012-05-11 22:03:40 +03:00
//NOTE: this will pick last dwelling with this creature (Mantis #900)
//check for block map equality is better but more complex solution
BOOST_FOREACH ( auto & iter , VLC - > objh - > cregens )
if ( iter . second = = cid )
result = std : : pair < int , int > ( 17 , iter . first ) ;
2012-06-01 14:35:31 +03:00
if ( result . first = = - 1 )
tlog0 < < " Error: failed to find creature for dwelling of " < < int ( faction ) < < " of level " < < int ( level ) < < " \n " ;
2012-05-11 22:03:40 +03:00
return result ;
2008-06-30 03:06:41 +03:00
}
}
return std : : pair < int , int > ( - 1 , - 1 ) ;
}
2010-01-01 20:54:31 +02:00
2008-06-30 03:06:41 +03:00
void CGameState : : randomizeObject ( CGObjectInstance * cur )
2012-02-16 20:10:58 +03:00
{
2008-06-30 03:06:41 +03:00
std : : pair < int , int > ran = pickObject ( cur ) ;
if ( ran . first < 0 | | ran . second < 0 ) //this is not a random object, or we couldn't find anything
{
2011-12-14 00:23:17 +03:00
if ( cur - > ID = = GameConstants : : TOWNI_TYPE ) //town - set def
2008-06-30 03:06:41 +03:00
{
CGTownInstance * t = dynamic_cast < CGTownInstance * > ( cur ) ;
2010-01-29 22:52:45 +02:00
t - > town = & VLC - > townh - > towns [ t - > subID ] ;
2008-06-30 03:06:41 +03:00
if ( t - > hasCapitol ( ) )
t - > defInfo = capitols [ t - > subID ] ;
else if ( t - > hasFort ( ) )
t - > defInfo = forts [ t - > subID ] ;
else
2012-02-16 20:10:58 +03:00
t - > defInfo = villages [ t - > subID ] ;
2008-06-30 03:06:41 +03:00
}
return ;
}
2011-12-14 00:23:17 +03:00
else if ( ran . first = = GameConstants : : HEROI_TYPE ) //special code for hero
2008-06-30 03:06:41 +03:00
{
CGHeroInstance * h = dynamic_cast < CGHeroInstance * > ( cur ) ;
2008-09-19 15:09:15 +03:00
if ( ! h ) { tlog2 < < " Wrong random hero at " < < cur - > pos < < std : : endl ; return ; }
2008-06-30 03:06:41 +03:00
cur - > ID = ran . first ;
2008-08-06 01:11:32 +03:00
h - > portrait = cur - > subID = ran . second ;
2008-06-30 03:06:41 +03:00
h - > type = VLC - > heroh - > heroes [ ran . second ] ;
2010-05-02 21:20:26 +03:00
h - > randomizeArmy ( h - > type - > heroType / 2 ) ;
2008-06-30 03:06:41 +03:00
map - > heroes . push_back ( h ) ;
return ; //TODO: maybe we should do something with definfo?
}
2011-12-14 00:23:17 +03:00
else if ( ran . first = = GameConstants : : TOWNI_TYPE ) //special code for town
2008-06-30 03:06:41 +03:00
{
CGTownInstance * t = dynamic_cast < CGTownInstance * > ( cur ) ;
2008-09-19 15:09:15 +03:00
if ( ! t ) { tlog2 < < " Wrong random town at " < < cur - > pos < < std : : endl ; return ; }
2008-06-30 03:06:41 +03:00
cur - > ID = ran . first ;
cur - > subID = ran . second ;
t - > town = & VLC - > townh - > towns [ ran . second ] ;
if ( t - > hasCapitol ( ) )
t - > defInfo = capitols [ t - > subID ] ;
else if ( t - > hasFort ( ) )
t - > defInfo = forts [ t - > subID ] ;
else
2012-02-16 20:10:58 +03:00
t - > defInfo = villages [ t - > subID ] ;
2010-05-02 21:20:26 +03:00
t - > randomizeArmy ( t - > subID ) ;
2008-06-30 03:06:41 +03:00
map - > towns . push_back ( t ) ;
return ;
}
//we have to replace normal random object
cur - > ID = ran . first ;
cur - > subID = ran . second ;
2009-02-11 19:03:30 +02:00
map - > removeBlockVisTiles ( cur ) ; //recalculate blockvis tiles - picked object might have different than random placeholder
2009-01-06 20:42:20 +02:00
map - > defy . push_back ( cur - > defInfo = VLC - > dobjinfo - > gobjs [ ran . first ] [ ran . second ] ) ;
2008-08-06 01:11:32 +03:00
if ( ! cur - > defInfo )
{
2008-09-19 15:09:15 +03:00
tlog1 < < " *BIG* WARNING: Missing def declaration for " < < cur - > ID < < " " < < cur - > subID < < std : : endl ;
2008-08-06 01:11:32 +03:00
return ;
}
2009-02-11 19:03:30 +02:00
map - > addBlockVisTiles ( cur ) ;
2008-06-30 03:06:41 +03:00
}
2008-07-25 20:28:28 +03:00
int CGameState : : getDate ( int mode ) const
{
int temp ;
switch ( mode )
{
2010-06-29 12:59:14 +03:00
case 0 : //day number
2008-07-25 20:28:28 +03:00
return day ;
break ;
2010-06-29 12:59:14 +03:00
case 1 : //day of week
2010-08-15 19:24:58 +03:00
temp = ( day ) % 7 ; // 1 - Monday, 7 - Sunday
2008-07-25 20:28:28 +03:00
if ( temp )
return temp ;
else return 7 ;
break ;
2010-06-29 12:59:14 +03:00
case 2 : //current week
2008-07-25 20:28:28 +03:00
temp = ( ( day - 1 ) / 7 ) + 1 ;
if ( ! ( temp % 4 ) )
return 4 ;
2012-02-16 20:10:58 +03:00
else
2008-07-25 20:28:28 +03:00
return ( temp % 4 ) ;
break ;
2010-06-29 12:59:14 +03:00
case 3 : //current month
2012-02-16 20:10:58 +03:00
return ( ( day - 1 ) / 28 ) + 1 ;
2008-07-25 20:28:28 +03:00
break ;
2010-08-22 10:11:46 +03:00
case 4 : //day of month
temp = ( day ) % 28 ;
if ( temp )
return temp ;
else return 28 ;
break ;
2008-07-25 20:28:28 +03:00
}
return 0 ;
}
2008-07-27 20:07:37 +03:00
CGameState : : CGameState ( )
{
2011-05-10 01:20:47 +03:00
gs = this ;
2008-07-27 20:07:37 +03:00
mx = new boost : : shared_mutex ( ) ;
2010-09-03 21:42:54 +03:00
applierGs = new CApplier < CBaseForGSApply > ;
registerTypes2 ( * applierGs ) ;
2009-09-07 05:29:44 +03:00
objCaller = new CObjectCallersHandler ;
2011-07-13 21:39:02 +03:00
globalEffects . setDescription ( " Global effects " ) ;
2008-07-27 20:07:37 +03:00
}
CGameState : : ~ CGameState ( )
{
2012-01-19 17:33:22 +03:00
//delete mx;//TODO: crash on Linux (mutex must be unlocked before destruction)
2011-02-06 19:26:27 +02:00
map . dellNull ( ) ;
curB . dellNull ( ) ;
2010-11-03 13:34:25 +02:00
//delete scenarioOps; //TODO: fix for loading ind delete
//delete initialOpts;
2009-03-15 17:13:54 +02:00
delete applierGs ;
2009-09-07 05:29:44 +03:00
delete objCaller ;
2010-08-01 17:04:48 +03:00
//TODO: delete properly that definfos
villages . clear ( ) ;
capitols . clear ( ) ;
2008-07-27 20:07:37 +03:00
}
2010-07-31 16:55:05 +03:00
2010-12-25 21:23:30 +02:00
BattleInfo * CGameState : : setupBattle ( int3 tile , const CArmedInstance * armies [ 2 ] , const CGHeroInstance * heroes [ 2 ] , bool creatureBank , const CGTownInstance * town )
2010-12-22 22:14:40 +02:00
{
2012-04-08 05:29:11 +03:00
const TerrainTile & t = map - > getTile ( tile ) ;
int terrain = t . tertype ;
if ( t . isCoastal ( ) & & ! t . isWater ( ) )
terrain = TerrainTile : : sand ;
2010-12-25 21:23:30 +02:00
int terType = battleGetBattlefieldType ( tile ) ;
return BattleInfo : : setupBattle ( tile , terrain , terType , armies , heroes , creatureBank , town ) ;
2010-12-22 22:14:40 +02:00
}
2012-04-14 05:20:22 +03:00
void CGameState : : init ( StartInfo * si )
2010-12-22 22:14:40 +02:00
{
2010-12-25 21:23:30 +02:00
struct HLP
2010-07-31 16:55:05 +03:00
{
2010-08-01 17:40:34 +03:00
//it's assumed that given hero should receive the bonus
2012-02-17 22:30:40 +03:00
static void giveCampaignBonusToHero ( CGHeroInstance * hero , const StartInfo * si , const CScenarioTravel & st , CGameState * gs )
2010-07-31 16:55:05 +03:00
{
const CScenarioTravel : : STravelBonus & curBonus = st . bonusesToChoose [ si - > choosenCampaignBonus ] ;
2010-08-01 17:40:34 +03:00
if ( curBonus . isBonusForHero ( ) )
2010-07-31 16:55:05 +03:00
{
//apply bonus
switch ( curBonus . type )
{
case 0 : //spell
hero - > spells . insert ( curBonus . info2 ) ;
break ;
case 1 : //monster
2010-08-01 17:40:34 +03:00
{
2011-12-14 00:23:17 +03:00
for ( int i = 0 ; i < GameConstants : : ARMY_SIZE ; i + + )
2010-08-01 17:40:34 +03:00
{
2010-11-22 02:34:46 +02:00
if ( hero - > slotEmpty ( i ) )
2010-08-01 17:40:34 +03:00
{
2010-11-22 02:34:46 +02:00
hero - > addToSlot ( i , curBonus . info2 , curBonus . info3 ) ;
2010-08-01 17:40:34 +03:00
break ;
}
}
}
2010-07-31 16:55:05 +03:00
break ;
case 3 : //artifact
2012-02-17 22:30:40 +03:00
gs - > giveHeroArtifact ( hero , curBonus . info2 ) ;
2010-07-31 16:55:05 +03:00
break ;
case 4 : //spell scroll
2011-02-23 13:21:40 +02:00
{
CArtifactInstance * scroll = CArtifactInstance : : createScroll ( VLC - > spellh - > spells [ curBonus . info2 ] ) ;
2012-04-14 05:20:22 +03:00
scroll - > putAt ( ArtifactLocation ( hero , scroll - > firstAvailableSlot ( hero ) ) ) ;
2011-02-23 13:21:40 +02:00
}
2010-07-31 16:55:05 +03:00
break ;
case 5 : //prim skill
{
2010-08-01 15:52:42 +03:00
const ui8 * ptr = reinterpret_cast < const ui8 * > ( & curBonus . info2 ) ;
2011-12-14 00:23:17 +03:00
for ( int g = 0 ; g < GameConstants : : PRIMARY_SKILLS ; + + g )
2010-07-31 16:55:05 +03:00
{
int val = ptr [ g ] ;
if ( val = = 0 )
{
continue ;
}
2010-11-19 00:06:56 +02:00
Bonus * bb = new Bonus ( Bonus : : PERMANENT , Bonus : : PRIMARY_SKILL , Bonus : : CAMPAIGN_BONUS , val , si - > whichMapInCampaign , g ) ;
hero - > addNewBonus ( bb ) ;
2010-07-31 16:55:05 +03:00
}
}
break ;
case 6 : //sec skills
2010-12-23 22:18:10 +02:00
hero - > setSecSkillLevel ( static_cast < CGHeroInstance : : SecondarySkill > ( curBonus . info2 ) , curBonus . info3 , true ) ;
2010-07-31 16:55:05 +03:00
break ;
}
}
}
static std : : vector < const PlayerSettings * > getHumanPlayerInfo ( const StartInfo * si )
{
std : : vector < const PlayerSettings * > ret ;
2012-02-16 20:10:58 +03:00
for ( std : : map < int , PlayerSettings > : : const_iterator it = si - > playerInfos . begin ( ) ;
2010-08-03 14:36:52 +03:00
it ! = si - > playerInfos . end ( ) ; + + it )
2010-07-31 16:55:05 +03:00
{
2010-08-03 14:36:52 +03:00
if ( it - > second . human )
ret . push_back ( & it - > second ) ;
2010-07-31 16:55:05 +03:00
}
return ret ;
}
2012-02-16 20:10:58 +03:00
static void replaceHero ( CGameState * gs , int objId , CGHeroInstance * ghi )
2010-08-30 17:52:18 +03:00
{
ghi - > id = objId ;
gs - > map - > objects [ objId ] = ghi ;
gs - > map - > heroes . push_back ( ghi ) ;
}
//sort in descending order by power
static bool heroPowerSorter ( const CGHeroInstance * a , const CGHeroInstance * b )
{
return a - > getHeroStrength ( ) > b - > getHeroStrength ( ) ;
}
2010-07-31 16:55:05 +03:00
} ;
2010-08-18 12:50:25 +03:00
2012-04-14 05:20:22 +03:00
tlog0 < < " \t Using random seed: " < < si - > seedToBeUsed < < std : : endl ;
ran . seed ( ( boost : : int32_t ) si - > seedToBeUsed ) ;
2010-10-27 14:36:14 +03:00
scenarioOps = new StartInfo ( * si ) ;
initialOpts = new StartInfo ( * si ) ;
si = NULL ;
switch ( scenarioOps - > mode )
2010-05-08 21:56:38 +03:00
{
2010-08-18 12:50:25 +03:00
case StartInfo : : NEW_GAME :
2010-10-27 14:36:14 +03:00
map = new Mapa ( scenarioOps - > mapname ) ;
2010-05-08 21:56:38 +03:00
break ;
2010-08-18 12:50:25 +03:00
case StartInfo : : CAMPAIGN :
2010-06-28 08:07:21 +03:00
{
2010-08-18 12:50:25 +03:00
campaign = new CCampaignState ( ) ;
2010-10-27 14:36:14 +03:00
campaign - > initNewCampaign ( * scenarioOps ) ;
assert ( vstd : : contains ( campaign - > camp - > mapPieces , scenarioOps - > whichMapInCampaign ) ) ;
2010-08-18 12:50:25 +03:00
2010-10-27 14:36:14 +03:00
std : : string & mapContent = campaign - > camp - > mapPieces [ scenarioOps - > whichMapInCampaign ] ;
2010-08-18 12:50:25 +03:00
map = new Mapa ( ) ;
2011-12-14 00:23:17 +03:00
map - > initFromBytes ( ( const ui8 * ) mapContent . c_str ( ) , mapContent . size ( ) ) ;
2010-06-28 08:07:21 +03:00
}
2010-05-08 21:56:38 +03:00
break ;
2010-12-22 22:14:40 +02:00
case StartInfo : : DUEL :
{
2011-01-21 04:36:30 +02:00
DuelParameters dp ;
try
{
2011-09-28 01:03:43 +03:00
CLoadFile lf ( scenarioOps - > mapname ) ;
lf > > dp ;
2011-01-21 04:36:30 +02:00
}
catch ( . . . )
{ }
const CArmedInstance * armies [ 2 ] = { 0 } ;
const CGHeroInstance * heroes [ 2 ] = { 0 } ;
CGTownInstance * town = NULL ;
for ( int i = 0 ; i < 2 ; i + + )
{
CArmedInstance * obj = NULL ;
if ( dp . sides [ i ] . heroId > = 0 )
{
CGHeroInstance * h = new CGHeroInstance ( ) ;
armies [ i ] = heroes [ i ] = h ;
obj = h ;
h - > subID = dp . sides [ i ] . heroId ;
h - > initHero ( h - > subID ) ;
}
else
{
CGCreature * c = new CGCreature ( ) ;
armies [ i ] = obj = c ;
c - > subID = 34 ;
2012-02-16 20:10:58 +03:00
2011-01-21 04:36:30 +02:00
}
obj - > initObj ( ) ;
obj - > setOwner ( i ) ;
for ( int j = 0 ; j < ARRAY_COUNT ( dp . sides [ i ] . stacks ) ; j + + )
{
int cre = dp . sides [ i ] . stacks [ j ] . type , count = dp . sides [ i ] . stacks [ j ] . count ;
2011-05-30 22:20:14 +03:00
if ( count | | obj - > hasStackAtSlot ( j ) )
2011-01-21 04:36:30 +02:00
obj - > setCreature ( j , cre , count ) ;
}
}
curB = BattleInfo : : setupBattle ( int3 ( ) , dp . bfieldType , dp . terType , armies , heroes , false , town ) ;
2010-12-23 02:33:48 +02:00
curB - > localInit ( ) ;
2010-12-22 22:14:40 +02:00
return ;
}
break ;
2010-08-18 12:50:25 +03:00
default :
2010-10-27 14:36:14 +03:00
tlog1 < < " Wrong mode: " < < ( int ) scenarioOps - > mode < < std : : endl ;
2010-08-18 12:50:25 +03:00
return ;
2010-05-08 21:56:38 +03:00
}
2010-08-18 12:50:25 +03:00
VLC - > arth - > initAllowedArtifactsList ( map - > allowedArtifact ) ;
2010-05-08 21:56:38 +03:00
tlog0 < < " Map loaded! " < < std : : endl ;
2010-08-18 12:50:25 +03:00
2010-05-08 21:56:38 +03:00
//tlog0 <<"Reading and detecting map file (together): "<<tmh.getDif()<<std::endl;
2012-04-14 05:20:22 +03:00
tlog0 < < " \t Our checksum for the map: " < < map - > checksum < < std : : endl ;
if ( scenarioOps - > mapfileChecksum )
2010-05-08 21:56:38 +03:00
{
2012-04-14 05:20:22 +03:00
tlog0 < < " \t Server checksum for " < < scenarioOps - > mapname < < " : " < < scenarioOps - > mapfileChecksum < < std : : endl ;
if ( map - > checksum ! = scenarioOps - > mapfileChecksum )
2010-05-08 21:56:38 +03:00
{
tlog1 < < " Wrong map checksum!!! " < < std : : endl ;
2012-04-22 10:32:45 +03:00
throw std : : runtime_error ( " Wrong checksum " ) ;
2010-05-08 21:56:38 +03:00
}
}
2012-04-14 05:20:22 +03:00
else
scenarioOps - > mapfileChecksum = map - > checksum ;
2010-05-08 21:56:38 +03:00
2008-07-26 16:57:32 +03:00
day = 0 ;
2008-11-28 03:36:34 +02:00
loadTownDInfos ( ) ;
2010-02-10 04:56:00 +02:00
//pick grail location
if ( map - > grailPos . x < 0 | | map - > grailRadious ) //grail not set or set within a radius around some place
{
if ( ! map - > grailRadious ) //radius not given -> anywhere on map
map - > grailRadious = map - > width * 2 ;
std : : vector < int3 > allowedPos ;
2012-02-16 20:10:58 +03:00
2010-02-10 04:56:00 +02:00
// add all not blocked tiles in range
for ( int i = 0 ; i < map - > width ; i + + )
{
for ( int j = 0 ; j < map - > height ; j + + )
{
for ( int k = 0 ; k < = map - > twoLevel ; k + + )
{
const TerrainTile & t = map - > terrain [ i ] [ j ] [ k ] ;
2012-02-16 20:10:58 +03:00
if ( ! t . blocked
& & ! t . visitable
& & t . tertype ! = TerrainTile : : water
2010-02-10 04:56:00 +02:00
& & t . tertype ! = TerrainTile : : rock
& & map - > grailPos . dist2d ( int3 ( i , j , k ) ) < = map - > grailRadious )
allowedPos . push_back ( int3 ( i , j , k ) ) ;
}
}
}
2012-02-16 20:10:58 +03:00
2010-02-10 04:56:00 +02:00
//remove tiles with holes
2011-12-14 00:23:17 +03:00
for ( ui32 no = 0 ; no < map - > objects . size ( ) ; + + no )
2010-02-10 04:56:00 +02:00
if ( map - > objects [ no ] - > ID = = 124 )
allowedPos - = map - > objects [ no ] - > pos ;
if ( allowedPos . size ( ) )
map - > grailPos = allowedPos [ ran ( ) % allowedPos . size ( ) ] ;
else
tlog2 < < " Warning: Grail cannot be placed, no appropriate tile found! \n " ;
}
2008-06-30 03:06:41 +03:00
//picking random factions for players
2012-02-16 20:10:58 +03:00
for ( std : : map < int , PlayerSettings > : : iterator it = scenarioOps - > playerInfos . begin ( ) ;
2010-08-03 14:36:52 +03:00
it ! = scenarioOps - > playerInfos . end ( ) ; + + it )
2008-06-30 03:06:41 +03:00
{
2010-08-03 14:36:52 +03:00
if ( it - > second . castle = = - 1 )
2008-06-30 03:06:41 +03:00
{
int f ;
do
{
2011-12-14 00:23:17 +03:00
f = ran ( ) % GameConstants : : F_NUMBER ;
2010-08-03 14:36:52 +03:00
} while ( ! ( map - > players [ it - > first ] . allowedFactions & 1 < < f ) ) ;
it - > second . castle = f ;
2008-06-30 03:06:41 +03:00
}
}
2010-02-10 04:56:00 +02:00
2008-06-30 03:06:41 +03:00
//randomizing objects
2010-07-09 07:29:11 +03:00
BOOST_FOREACH ( CGObjectInstance * obj , map - > objects )
2008-06-30 03:06:41 +03:00
{
2010-07-09 07:29:11 +03:00
randomizeObject ( obj ) ;
obj - > hoverName = VLC - > generaltexth - > names [ obj - > ID ] ;
//handle Favouring Winds - mark tiles under it
if ( obj - > ID = = 225 )
for ( int i = 0 ; i < obj - > getWidth ( ) ; i + + )
for ( int j = 0 ; j < obj - > getHeight ( ) ; j + + )
{
int3 pos = obj - > pos - int3 ( i , j , 0 ) ;
if ( map - > isInTheMap ( pos ) )
map - > getTile ( pos ) . siodmyTajemniczyBajt | = 128 ;
}
2008-06-30 03:06:41 +03:00
}
//std::cout<<"\tRandomizing objects: "<<th.getDif()<<std::endl;
2010-08-02 17:29:30 +03:00
/*********creating players entries in gs****************************************/
2012-02-16 20:10:58 +03:00
for ( std : : map < int , PlayerSettings > : : iterator it = scenarioOps - > playerInfos . begin ( ) ;
2010-08-03 14:36:52 +03:00
it ! = scenarioOps - > playerInfos . end ( ) ; + + it )
2010-08-02 17:29:30 +03:00
{
2010-08-03 14:36:52 +03:00
std : : pair < int , PlayerState > ins ( it - > first , PlayerState ( ) ) ;
2010-08-02 17:29:30 +03:00
ins . second . color = ins . first ;
2010-08-03 14:36:52 +03:00
ins . second . human = it - > second . human ;
2010-08-03 15:34:06 +03:00
ins . second . team = map - > players [ ins . first ] . team ;
2010-08-06 16:14:10 +03:00
teams [ ins . second . team ] . id = ins . second . team ; //init team
teams [ ins . second . team ] . players . insert ( ins . first ) ; //add player to team
2010-08-02 17:29:30 +03:00
players . insert ( ins ) ;
}
2008-08-27 13:19:18 +03:00
/*********give starting hero****************************************/
2011-12-14 00:23:17 +03:00
for ( int i = 0 ; i < GameConstants : : PLAYER_LIMIT ; i + + )
2008-07-27 20:07:37 +03:00
{
2011-02-04 16:58:14 +02:00
const PlayerInfo & p = map - > players [ i ] ;
2011-03-19 16:35:29 +02:00
bool generateHero = ( p . generateHeroAtMainTown & & p . hasMainTown ) ;
2011-02-04 16:58:14 +02:00
if ( generateHero & & vstd : : contains ( scenarioOps - > playerInfos , i ) )
2008-07-27 20:07:37 +03:00
{
2011-02-04 16:58:14 +02:00
int3 hpos = p . posOfMainTown ;
hpos . x + = 1 ;
2009-08-27 11:04:32 +03:00
2011-02-04 16:58:14 +02:00
int h = pickHero ( i ) ;
2010-08-03 14:36:52 +03:00
if ( scenarioOps - > playerInfos [ i ] . hero = = - 1 )
scenarioOps - > playerInfos [ i ] . hero = h ;
2009-08-27 11:04:32 +03:00
2011-12-14 00:23:17 +03:00
CGHeroInstance * nnn = static_cast < CGHeroInstance * > ( createObject ( GameConstants : : HEROI_TYPE , h , hpos , i ) ) ;
2008-07-27 20:07:37 +03:00
nnn - > id = map - > objects . size ( ) ;
2008-10-26 22:58:34 +02:00
nnn - > initHero ( ) ;
2008-07-27 20:07:37 +03:00
map - > heroes . push_back ( nnn ) ;
map - > objects . push_back ( nnn ) ;
2008-09-17 13:18:22 +03:00
map - > addBlockVisTiles ( nnn ) ;
2008-07-27 20:07:37 +03:00
}
}
2008-06-30 03:06:41 +03:00
2010-08-30 17:52:18 +03:00
/*************************replace hero placeholders*****************************/
if ( campaign )
{
CScenarioTravel : : STravelBonus bonus =
2010-10-24 14:35:14 +03:00
campaign - > camp - > scenarios [ scenarioOps - > whichMapInCampaign ] . travelOptions . bonusesToChoose [ scenarioOps - > choosenCampaignBonus ] ;
2010-08-30 17:52:18 +03:00
2010-09-04 17:49:15 +03:00
std : : vector < CGHeroInstance * > Xheroes ;
if ( bonus . type = = 8 ) //hero crossover
{
Xheroes = campaign - > camp - > scenarios [ bonus . info2 ] . crossoverHeroes ;
}
//selecting heroes by type
2010-08-30 17:52:18 +03:00
for ( int g = 0 ; g < map - > objects . size ( ) ; + + g )
{
CGObjectInstance * obj = map - > objects [ g ] ;
if ( obj - > ID ! = 214 ) //not a placeholder
{
continue ;
}
CGHeroPlaceholder * hp = static_cast < CGHeroPlaceholder * > ( obj ) ;
2010-09-04 17:49:15 +03:00
if ( hp - > subID ! = 0xFF ) //select by type
2010-08-30 17:52:18 +03:00
{
2010-09-04 17:49:15 +03:00
bool found = false ;
2010-08-30 17:52:18 +03:00
BOOST_FOREACH ( CGHeroInstance * ghi , Xheroes )
{
if ( ghi - > subID = = hp - > subID )
{
2010-09-04 17:49:15 +03:00
found = true ;
2010-08-30 17:52:18 +03:00
HLP : : replaceHero ( this , g , ghi ) ;
2010-09-04 17:49:15 +03:00
Xheroes - = ghi ;
2010-08-30 17:52:18 +03:00
break ;
}
}
2010-09-04 17:49:15 +03:00
if ( ! found )
{
//TODO: create new hero of this type
}
}
}
//selecting heroes by power
std : : sort ( Xheroes . begin ( ) , Xheroes . end ( ) , HLP : : heroPowerSorter ) ;
for ( int g = 0 ; g < map - > objects . size ( ) ; + + g )
{
CGObjectInstance * obj = map - > objects [ g ] ;
if ( obj - > ID ! = 214 ) //not a placeholder
{
continue ;
}
CGHeroPlaceholder * hp = static_cast < CGHeroPlaceholder * > ( obj ) ;
if ( hp - > subID = = 0xFF ) //select by power
{
2010-10-30 21:54:59 +03:00
if ( Xheroes . size ( ) > hp - > power - 1 )
HLP : : replaceHero ( this , g , Xheroes [ hp - > power - 1 ] ) ;
else
tlog2 < < " Warning, to hero to replace! \n " ;
2010-09-04 17:49:15 +03:00
//we don't have to remove hero from Xheroes because it would destroy the order and duplicates shouldn't happen
2010-08-30 17:52:18 +03:00
}
}
}
2008-06-30 03:06:41 +03:00
/******************RESOURCES****************************************************/
2011-07-05 09:14:07 +03:00
TResources startresAI , startresHuman ;
2011-12-14 00:23:17 +03:00
const JsonNode config ( GameConstants : : DATA_DIR + " /config/startres.json " ) ;
2011-08-20 05:53:57 +03:00
const JsonVector & vector = config [ " difficulty " ] . Vector ( ) ;
const JsonNode & level = vector [ scenarioOps - > difficulty ] ;
const JsonNode & human = level [ " human " ] ;
const JsonNode & ai = level [ " ai " ] ;
startresHuman [ 0 ] = human [ " wood " ] . Float ( ) ;
startresHuman [ 1 ] = human [ " mercury " ] . Float ( ) ;
startresHuman [ 2 ] = human [ " ore " ] . Float ( ) ;
startresHuman [ 3 ] = human [ " sulfur " ] . Float ( ) ;
startresHuman [ 4 ] = human [ " crystal " ] . Float ( ) ;
startresHuman [ 5 ] = human [ " gems " ] . Float ( ) ;
startresHuman [ 6 ] = human [ " gold " ] . Float ( ) ;
startresHuman [ 7 ] = human [ " mithril " ] . Float ( ) ;
startresAI [ 0 ] = ai [ " wood " ] . Float ( ) ;
startresAI [ 1 ] = ai [ " mercury " ] . Float ( ) ;
startresAI [ 2 ] = ai [ " ore " ] . Float ( ) ;
startresAI [ 3 ] = ai [ " sulfur " ] . Float ( ) ;
startresAI [ 4 ] = ai [ " crystal " ] . Float ( ) ;
startresAI [ 5 ] = ai [ " gems " ] . Float ( ) ;
startresAI [ 6 ] = ai [ " gold " ] . Float ( ) ;
startresAI [ 7 ] = ai [ " mithril " ] . Float ( ) ;
2011-07-05 09:14:07 +03:00
2008-07-25 20:28:28 +03:00
for ( std : : map < ui8 , PlayerState > : : iterator i = players . begin ( ) ; i ! = players . end ( ) ; i + + )
2008-06-30 03:06:41 +03:00
{
2011-07-05 09:14:07 +03:00
PlayerState & p = i - > second ;
if ( p . human )
p . resources = startresHuman ;
else
p . resources = startresAI ;
2010-07-31 16:55:05 +03:00
}
//give start resource bonus in case of campaign
2010-10-24 14:35:14 +03:00
if ( scenarioOps - > mode = = StartInfo : : CAMPAIGN )
2010-07-31 16:55:05 +03:00
{
2012-02-16 20:10:58 +03:00
CScenarioTravel : : STravelBonus chosenBonus =
2010-10-24 14:35:14 +03:00
campaign - > camp - > scenarios [ scenarioOps - > whichMapInCampaign ] . travelOptions . bonusesToChoose [ scenarioOps - > choosenCampaignBonus ] ;
2010-07-31 16:55:05 +03:00
if ( chosenBonus . type = = 7 ) //resource
{
2010-10-24 14:35:14 +03:00
std : : vector < const PlayerSettings * > people = HLP : : getHumanPlayerInfo ( scenarioOps ) ; //players we will give resource bonus
2011-07-05 09:14:07 +03:00
BOOST_FOREACH ( const PlayerSettings * ps , people )
2010-07-31 16:55:05 +03:00
{
std : : vector < int > res ; //resources we will give
switch ( chosenBonus . info1 )
{
case 0 : case 1 : case 2 : case 3 : case 4 : case 5 : case 6 :
res . push_back ( chosenBonus . info1 ) ;
break ;
case 0xFD : //wood+ore
2011-07-05 09:14:07 +03:00
res . push_back ( Res : : WOOD ) ; res . push_back ( Res : : ORE ) ;
2010-07-31 16:55:05 +03:00
break ;
case 0xFE : //rare
2011-07-05 09:14:07 +03:00
res . push_back ( Res : : MERCURY ) ; res . push_back ( Res : : SULFUR ) ; res . push_back ( Res : : CRYSTAL ) ; res . push_back ( Res : : GEMS ) ;
2010-07-31 16:55:05 +03:00
break ;
default :
assert ( 0 ) ;
break ;
}
//increasing resource quantity
for ( int n = 0 ; n < res . size ( ) ; + + n )
{
2011-07-05 09:14:07 +03:00
players [ ps - > color ] . resources [ res [ n ] ] + = chosenBonus . info2 ;
2010-07-31 16:55:05 +03:00
}
}
}
2008-06-30 03:06:41 +03:00
}
2008-09-07 06:38:37 +03:00
2008-06-30 03:06:41 +03:00
/*************************HEROES************************************************/
2010-07-08 08:52:11 +03:00
std : : set < int > hids ; //hero ids to create pool
2011-12-14 00:23:17 +03:00
for ( ui32 i = 0 ; i < map - > allowedHeroes . size ( ) ; i + + ) //add to hids all allowed heroes
2008-10-26 22:58:34 +02:00
if ( map - > allowedHeroes [ i ] )
hids . insert ( i ) ;
2010-07-08 08:52:11 +03:00
2011-12-14 00:23:17 +03:00
for ( ui32 i = 0 ; i < map - > heroes . size ( ) ; i + + ) //heroes instances initialization
2008-06-30 03:06:41 +03:00
{
if ( map - > heroes [ i ] - > getOwner ( ) < 0 )
{
2008-10-26 22:58:34 +02:00
tlog2 < < " Warning - hero with uninitialized owner! \n " ;
continue ;
2008-06-30 03:06:41 +03:00
}
2008-10-26 22:58:34 +02:00
CGHeroInstance * vhi = ( map - > heroes [ i ] ) ;
vhi - > initHero ( ) ;
2008-12-22 19:48:41 +02:00
players . find ( vhi - > getOwner ( ) ) - > second . heroes . push_back ( vhi ) ;
2008-10-26 22:58:34 +02:00
hids . erase ( vhi - > subID ) ;
}
2010-07-08 08:52:11 +03:00
2011-12-14 00:23:17 +03:00
for ( ui32 i = 0 ; i < map - > objects . size ( ) ; i + + ) //prisons
2010-02-10 23:31:54 +02:00
{
if ( map - > objects [ i ] - > ID = = 62 )
hids . erase ( map - > objects [ i ] - > subID ) ;
}
2010-07-08 08:52:11 +03:00
2011-12-14 00:23:17 +03:00
for ( ui32 i = 0 ; i < map - > predefinedHeroes . size ( ) ; i + + )
2008-10-26 22:58:34 +02:00
{
if ( ! vstd : : contains ( hids , map - > predefinedHeroes [ i ] - > subID ) )
continue ;
map - > predefinedHeroes [ i ] - > initHero ( ) ;
hpool . heroesPool [ map - > predefinedHeroes [ i ] - > subID ] = map - > predefinedHeroes [ i ] ;
hpool . pavailable [ map - > predefinedHeroes [ i ] - > subID ] = 0xff ;
hids . erase ( map - > predefinedHeroes [ i ] - > subID ) ;
}
2010-07-08 08:52:11 +03:00
BOOST_FOREACH ( int hid , hids ) //all not used allowed heroes go with default state into the pool
2008-10-26 22:58:34 +02:00
{
CGHeroInstance * vhi = new CGHeroInstance ( ) ;
vhi - > initHero ( hid ) ;
hpool . heroesPool [ hid ] = vhi ;
hpool . pavailable [ hid ] = 0xff ;
}
2010-07-08 08:52:11 +03:00
2011-12-14 00:23:17 +03:00
for ( ui32 i = 0 ; i < map - > disposedHeroes . size ( ) ; i + + )
2008-10-26 22:58:34 +02:00
{
hpool . pavailable [ map - > disposedHeroes [ i ] . ID ] = map - > disposedHeroes [ i ] . players ;
2008-06-30 03:06:41 +03:00
}
2010-07-08 08:52:11 +03:00
2010-10-24 14:35:14 +03:00
if ( scenarioOps - > mode = = StartInfo : : CAMPAIGN ) //give campaign bonuses for specific / best hero
2010-08-01 15:52:42 +03:00
{
2012-02-16 20:10:58 +03:00
CScenarioTravel : : STravelBonus chosenBonus =
2010-10-24 14:35:14 +03:00
campaign - > camp - > scenarios [ scenarioOps - > whichMapInCampaign ] . travelOptions . bonusesToChoose [ scenarioOps - > choosenCampaignBonus ] ;
2010-08-01 15:52:42 +03:00
if ( chosenBonus . isBonusForHero ( ) & & chosenBonus . info1 ! = 0xFFFE ) //exclude generated heroes
{
//find human player
int humanPlayer ;
for ( std : : map < ui8 , PlayerState > : : iterator it = players . begin ( ) ; it ! = players . end ( ) ; + + it )
{
if ( it - > second . human )
{
humanPlayer = it - > first ;
break ;
}
}
2010-12-20 15:04:24 +02:00
std : : vector < ConstTransitivePtr < CGHeroInstance > > & heroes = players [ humanPlayer ] . heroes ;
2010-08-01 15:52:42 +03:00
if ( chosenBonus . info1 = = 0xFFFD ) //most powerful
{
int maxB = - 1 ;
for ( int b = 0 ; b < heroes . size ( ) ; + + b )
{
if ( maxB = = - 1 | | heroes [ b ] - > getTotalStrength ( ) > heroes [ maxB ] - > getTotalStrength ( ) )
{
maxB = b ;
}
}
2010-10-30 21:54:59 +03:00
if ( maxB < 0 )
tlog2 < < " Warning - cannot give bonus to hero cause there are no heroes! \n " ;
else
2012-02-17 22:30:40 +03:00
HLP : : giveCampaignBonusToHero ( heroes [ maxB ] , scenarioOps , campaign - > camp - > scenarios [ scenarioOps - > whichMapInCampaign ] . travelOptions , this ) ;
2010-08-01 15:52:42 +03:00
}
else //specific hero
{
for ( int b = 0 ; b < heroes . size ( ) ; + + b )
{
if ( heroes [ b ] - > subID = = chosenBonus . info1 )
{
2012-02-17 22:30:40 +03:00
HLP : : giveCampaignBonusToHero ( heroes [ b ] , scenarioOps , campaign - > camp - > scenarios [ scenarioOps - > whichMapInCampaign ] . travelOptions , this ) ;
2010-08-01 15:52:42 +03:00
break ;
}
}
}
}
}
2010-08-03 15:34:06 +03:00
/*************************FOG**OF**WAR******************************************/
for ( std : : map < ui8 , TeamState > : : iterator k = teams . begin ( ) ; k ! = teams . end ( ) ; + + k )
2008-06-30 03:06:41 +03:00
{
k - > second . fogOfWarMap . resize ( map - > width ) ;
for ( int g = 0 ; g < map - > width ; + + g )
k - > second . fogOfWarMap [ g ] . resize ( map - > height ) ;
for ( int g = - 0 ; g < map - > width ; + + g )
for ( int h = 0 ; h < map - > height ; + + h )
k - > second . fogOfWarMap [ g ] [ h ] . resize ( map - > twoLevel + 1 , 0 ) ;
for ( int g = 0 ; g < map - > width ; + + g )
for ( int h = 0 ; h < map - > height ; + + h )
for ( int v = 0 ; v < map - > twoLevel + 1 ; + + v )
k - > second . fogOfWarMap [ g ] [ h ] [ v ] = 0 ;
2009-03-12 01:25:59 +02:00
BOOST_FOREACH ( CGObjectInstance * obj , map - > objects )
2008-06-30 03:06:41 +03:00
{
2010-08-03 15:34:06 +03:00
if ( ! vstd : : contains ( k - > second . players , obj - > tempOwner ) ) continue ; //not a flagged object
2009-03-12 01:25:59 +02:00
2011-01-20 19:25:15 +02:00
boost : : unordered_set < int3 , ShashInt3 > tiles ;
2009-11-11 19:45:03 +02:00
obj - > getSightTiles ( tiles ) ;
BOOST_FOREACH ( int3 tile , tiles )
{
k - > second . fogOfWarMap [ tile . x ] [ tile . y ] [ tile . z ] = 1 ;
}
2008-06-30 03:06:41 +03:00
}
2010-08-03 15:34:06 +03:00
}
2012-02-16 20:10:58 +03:00
2010-08-03 15:34:06 +03:00
for ( std : : map < ui8 , PlayerState > : : iterator k = players . begin ( ) ; k ! = players . end ( ) ; + + k )
{
2008-08-26 00:14:00 +03:00
//starting bonus
2010-10-24 14:35:14 +03:00
if ( scenarioOps - > playerInfos [ k - > first ] . bonus = = PlayerSettings : : brandom )
scenarioOps - > playerInfos [ k - > first ] . bonus = ran ( ) % 3 ;
switch ( scenarioOps - > playerInfos [ k - > first ] . bonus )
2008-08-26 00:14:00 +03:00
{
2010-07-31 16:55:05 +03:00
case PlayerSettings : : bgold :
2011-07-05 09:14:07 +03:00
k - > second . resources [ Res : : GOLD ] + = 500 + ( ran ( ) % 6 ) * 100 ;
2008-08-26 00:14:00 +03:00
break ;
2010-07-31 16:55:05 +03:00
case PlayerSettings : : bresource :
2008-08-26 00:14:00 +03:00
{
2010-10-24 14:35:14 +03:00
int res = VLC - > townh - > towns [ scenarioOps - > playerInfos [ k - > first ] . castle ] . primaryRes ;
2008-08-26 00:14:00 +03:00
if ( res = = 127 )
{
2011-07-05 09:14:07 +03:00
k - > second . resources [ Res : : WOOD ] + = 5 + ran ( ) % 6 ;
k - > second . resources [ Res : : ORE ] + = 5 + ran ( ) % 6 ;
2008-08-26 00:14:00 +03:00
}
else
{
k - > second . resources [ res ] + = 3 + ran ( ) % 4 ;
}
break ;
}
2010-07-31 16:55:05 +03:00
case PlayerSettings : : bartifact :
2008-08-26 00:14:00 +03:00
{
2010-07-06 08:09:06 +03:00
if ( ! k - > second . heroes . size ( ) )
{
tlog5 < < " Cannot give starting artifact - no heroes! " < < std : : endl ;
break ;
}
CArtifact * toGive ;
toGive = VLC - > arth - > artifacts [ VLC - > arth - > getRandomArt ( CArtifact : : ART_TREASURE ) ] ;
CGHeroInstance * hero = k - > second . heroes [ 0 ] ;
2012-02-17 22:30:40 +03:00
giveHeroArtifact ( hero , toGive - > id ) ;
2008-08-26 00:14:00 +03:00
}
2012-01-30 19:07:52 +03:00
break ;
2008-08-26 00:14:00 +03:00
}
2008-06-30 03:06:41 +03:00
}
/****************************TOWNS************************************************/
2010-07-20 17:08:13 +03:00
for ( int i = 0 ; i < 4 ; i + + )
CGTownInstance : : universitySkills . push_back ( 14 + i ) ; //skills for university
2012-02-16 20:10:58 +03:00
2011-12-14 00:23:17 +03:00
for ( ui32 i = 0 ; i < map - > towns . size ( ) ; i + + )
2008-06-30 03:06:41 +03:00
{
CGTownInstance * vti = ( map - > towns [ i ] ) ;
if ( ! vti - > town )
vti - > town = & VLC - > townh - > towns [ vti - > subID ] ;
if ( vti - > name . length ( ) = = 0 ) // if town hasn't name we draw it
2008-12-22 19:48:41 +02:00
vti - > name = vti - > town - > Names ( ) [ ran ( ) % vti - > town - > Names ( ) . size ( ) ] ;
2008-08-20 09:57:53 +03:00
//init buildings
2008-06-30 03:06:41 +03:00
if ( vti - > builtBuildings . find ( - 50 ) ! = vti - > builtBuildings . end ( ) ) //give standard set of buildings
{
vti - > builtBuildings . erase ( - 50 ) ;
vti - > builtBuildings . insert ( 10 ) ;
vti - > builtBuildings . insert ( 5 ) ;
vti - > builtBuildings . insert ( 30 ) ;
if ( ran ( ) % 2 )
vti - > builtBuildings . insert ( 31 ) ;
2010-06-30 22:27:35 +03:00
}
2012-02-16 20:10:58 +03:00
2010-07-20 17:08:13 +03:00
if ( vstd : : contains ( vti - > builtBuildings , ( 6 ) ) & & vti - > state ( ) = = 2 )
2010-06-30 22:27:35 +03:00
vti - > builtBuildings . erase ( 6 ) ; //if we have harbor without water - erase it (this is H3 behaviour)
2012-02-16 20:10:58 +03:00
2010-06-30 22:27:35 +03:00
//init hordes
2011-12-14 00:23:17 +03:00
for ( int i = 0 ; i < GameConstants : : CREATURES_PER_TOWN ; i + + )
2010-02-13 17:56:34 +02:00
if ( vstd : : contains ( vti - > builtBuildings , ( - 31 - i ) ) ) //if we have horde for this level
{
vti - > builtBuildings . erase ( - 31 - i ) ; //remove old ID
if ( vti - > town - > hordeLvl [ 0 ] = = i ) //if town first horde is this one
{
vti - > builtBuildings . insert ( 18 ) ; //add it
if ( vstd : : contains ( vti - > builtBuildings , ( 37 + i ) ) ) //if we have upgraded dwelling as well
vti - > builtBuildings . insert ( 19 ) ; //add it as well
}
if ( vti - > town - > hordeLvl [ 1 ] = = i ) //if town second horde is this one
{
vti - > builtBuildings . insert ( 24 ) ;
if ( vstd : : contains ( vti - > builtBuildings , ( 37 + i ) ) )
vti - > builtBuildings . insert ( 25 ) ;
}
}
2012-02-16 20:10:58 +03:00
2011-08-25 23:02:38 +03:00
//town events
BOOST_FOREACH ( CCastleEvent * ev , vti - > events )
{
2011-12-14 00:23:17 +03:00
for ( int i = 0 ; i < GameConstants : : CREATURES_PER_TOWN ; i + + )
2011-08-25 23:02:38 +03:00
if ( vstd : : contains ( ev - > buildings , ( - 31 - i ) ) ) //if we have horde for this level
2010-08-25 17:57:58 +03:00
{
2011-08-25 23:02:38 +03:00
ev - > buildings . erase ( - 31 - i ) ;
2010-08-25 17:57:58 +03:00
if ( vti - > town - > hordeLvl [ 0 ] = = i )
2011-08-25 23:02:38 +03:00
ev - > buildings . insert ( 18 ) ;
2010-08-25 17:57:58 +03:00
if ( vti - > town - > hordeLvl [ 1 ] = = i )
2011-08-25 23:02:38 +03:00
ev - > buildings . insert ( 24 ) ;
2010-08-25 17:57:58 +03:00
}
2011-08-25 23:02:38 +03:00
}
2008-08-20 09:57:53 +03:00
//init spells
2011-12-14 00:23:17 +03:00
vti - > spells . resize ( GameConstants : : SPELL_LEVELS ) ;
2008-08-20 09:57:53 +03:00
CSpell * s ;
2011-12-14 00:23:17 +03:00
for ( ui32 z = 0 ; z < vti - > obligatorySpells . size ( ) ; z + + )
2008-08-20 09:57:53 +03:00
{
2010-12-19 16:39:56 +02:00
s = VLC - > spellh - > spells [ vti - > obligatorySpells [ z ] ] ;
2008-08-20 09:57:53 +03:00
vti - > spells [ s - > level - 1 ] . push_back ( s - > id ) ;
vti - > possibleSpells - = s - > id ;
}
while ( vti - > possibleSpells . size ( ) )
{
2010-10-31 00:53:41 +03:00
ui32 total = 0 ;
int sel = - 1 ;
2011-12-14 00:23:17 +03:00
for ( ui32 ps = 0 ; ps < vti - > possibleSpells . size ( ) ; ps + + )
2010-12-19 16:39:56 +02:00
total + = VLC - > spellh - > spells [ vti - > possibleSpells [ ps ] ] - > probabilities [ vti - > subID ] ;
2008-08-20 09:57:53 +03:00
int r = ( total ) ? ran ( ) % total : - 1 ;
2011-12-14 00:23:17 +03:00
for ( ui32 ps = 0 ; ps < vti - > possibleSpells . size ( ) ; ps + + )
2008-08-20 09:57:53 +03:00
{
2010-12-19 16:39:56 +02:00
r - = VLC - > spellh - > spells [ vti - > possibleSpells [ ps ] ] - > probabilities [ vti - > subID ] ;
2008-08-20 09:57:53 +03:00
if ( r < 0 )
{
sel = ps ;
break ;
}
}
if ( sel < 0 )
sel = 0 ;
2010-12-19 16:39:56 +02:00
CSpell * s = VLC - > spellh - > spells [ vti - > possibleSpells [ sel ] ] ;
2008-08-20 09:57:53 +03:00
vti - > spells [ s - > level - 1 ] . push_back ( s - > id ) ;
vti - > possibleSpells - = s - > id ;
}
2009-03-09 12:37:49 +02:00
if ( vti - > getOwner ( ) ! = 255 )
getPlayer ( vti - > getOwner ( ) ) - > towns . push_back ( vti ) ;
2008-06-30 03:06:41 +03:00
}
2010-08-02 17:29:30 +03:00
//campaign bonuses for towns
2010-10-24 14:35:14 +03:00
if ( scenarioOps - > mode = = StartInfo : : CAMPAIGN )
2010-08-02 17:29:30 +03:00
{
2012-02-16 20:10:58 +03:00
CScenarioTravel : : STravelBonus chosenBonus =
2010-10-24 14:35:14 +03:00
campaign - > camp - > scenarios [ scenarioOps - > whichMapInCampaign ] . travelOptions . bonusesToChoose [ scenarioOps - > choosenCampaignBonus ] ;
2010-08-02 17:29:30 +03:00
if ( chosenBonus . type = = 2 )
{
for ( int g = 0 ; g < map - > towns . size ( ) ; + + g )
{
PlayerState * owner = getPlayer ( map - > towns [ g ] - > getOwner ( ) ) ;
2012-02-16 20:10:58 +03:00
if ( owner )
2010-08-02 17:29:30 +03:00
{
2012-02-16 20:10:58 +03:00
PlayerInfo & pi = map - > players [ owner - > color ] ;
if ( owner - > human & & //human-owned
map - > towns [ g ] - > pos = = pi . posOfMainTown + int3 ( 2 , 0 , 0 ) )
{
map - > towns [ g ] - > builtBuildings . insert (
CBuildingHandler : : campToERMU ( chosenBonus . info1 , map - > towns [ g ] - > town - > typeID , map - > towns [ g ] - > builtBuildings ) ) ;
break ;
}
2010-08-02 17:29:30 +03:00
}
}
}
}
2011-02-04 16:58:14 +02:00
objCaller - > preInit ( ) ;
BOOST_FOREACH ( CGObjectInstance * obj , map - > objects )
{
obj - > initObj ( ) ;
if ( obj - > ID = = 62 ) //prison also needs to initialize hero
static_cast < CGHeroInstance * > ( obj ) - > initHero ( ) ;
}
CGTeleport : : postInit ( ) ; //pairing subterranean gates
buildBonusSystemTree ( ) ;
2008-07-25 20:28:28 +03:00
for ( std : : map < ui8 , PlayerState > : : iterator k = players . begin ( ) ; k ! = players . end ( ) ; + + k )
2008-06-30 03:06:41 +03:00
{
2012-05-28 22:29:32 +03:00
if ( k - > first = = 255 )
2008-06-30 03:06:41 +03:00
continue ;
2008-08-20 09:57:53 +03:00
//init visiting and garrisoned heroes
2011-02-04 16:58:14 +02:00
BOOST_FOREACH ( CGHeroInstance * h , k - > second . heroes )
2012-02-16 20:10:58 +03:00
{
2011-02-04 16:58:14 +02:00
BOOST_FOREACH ( CGTownInstance * t , k - > second . towns )
2008-06-30 03:06:41 +03:00
{
2009-09-13 01:17:23 +03:00
int3 vistile = t - > pos ; vistile . x - - ; //tile next to the entrance
if ( vistile = = h - > pos | | h - > pos = = t - > pos )
2008-06-30 03:06:41 +03:00
{
2011-02-04 16:58:14 +02:00
t - > setVisitingHero ( h ) ;
2009-09-13 01:17:23 +03:00
if ( h - > pos = = t - > pos ) //visiting hero placed in the editor has same pos as the town - we need to correct it
{
map - > removeBlockVisTiles ( h ) ;
h - > pos . x - = 1 ;
map - > addBlockVisTiles ( h ) ;
}
2008-08-25 13:25:16 +03:00
break ;
2008-06-30 03:06:41 +03:00
}
}
}
}
2011-05-30 02:49:25 +03:00
map - > checkForObjectives ( ) ; //needs to be run when all objects are properly placed
2012-03-27 23:08:54 +03:00
2012-05-05 00:16:39 +03:00
int seedAfterInit = ran ( ) ;
tlog0 < < " Seed after init is " < < seedAfterInit < < " (before was " < < scenarioOps - > seedToBeUsed < < " ) " < < std : : endl ;
2012-04-14 05:20:22 +03:00
if ( scenarioOps - > seedPostInit > 0 )
2012-03-27 23:08:54 +03:00
{
2012-05-05 00:16:39 +03:00
//RNG must be in the same state on all machines when initialization is done (otherwise we have desync)
assert ( scenarioOps - > seedPostInit = = seedAfterInit ) ;
2012-04-14 05:20:22 +03:00
}
else
{
2012-05-05 00:16:39 +03:00
scenarioOps - > seedPostInit = seedAfterInit ; //store the post init "seed"
2012-03-27 23:08:54 +03:00
}
2008-06-30 03:06:41 +03:00
}
2008-05-27 16:16:35 +03:00
2012-04-23 22:56:37 +03:00
int CGameState : : battleGetBattlefieldType ( int3 tile ) const
2009-02-09 16:50:32 +02:00
{
2009-02-10 16:21:51 +02:00
if ( tile = = int3 ( ) & & curB )
tile = curB - > tile ;
else if ( tile = = int3 ( ) & & ! curB )
2009-02-09 16:50:32 +02:00
return - 1 ;
2009-02-10 16:21:51 +02:00
2010-07-31 03:26:34 +03:00
const TerrainTile & t = map - > getTile ( tile ) ;
//fight in mine -> subterranean
2010-11-09 13:27:58 +02:00
if ( dynamic_cast < const CGMine * > ( t . visitableObjects . front ( ) ) )
2010-07-31 03:26:34 +03:00
return 12 ;
2012-05-19 01:47:54 +03:00
BOOST_FOREACH ( auto & obj , map - > objects )
2009-07-01 18:58:20 +03:00
{
2012-05-19 14:47:26 +03:00
//look only for objects covering given tile
if ( ! obj | | obj - > pos . z ! = tile . z
| | ! obj - > coveringAt ( tile . x - obj - > pos . x , tile . y - obj - > pos . y ) )
2009-07-01 18:58:20 +03:00
continue ;
2012-04-23 22:56:37 +03:00
2012-05-19 01:47:54 +03:00
switch ( obj - > ID )
2009-07-01 18:58:20 +03:00
{
2012-04-23 22:56:37 +03:00
case Obj : : CLOVER_FIELD :
2009-07-01 18:58:20 +03:00
return 19 ;
2012-04-23 22:56:37 +03:00
case Obj : : CURSED_GROUND1 : case Obj : : CURSED_GROUND2 :
2009-07-01 18:58:20 +03:00
return 22 ;
2012-04-23 22:56:37 +03:00
case Obj : : EVIL_FOG :
2009-07-01 18:58:20 +03:00
return 20 ;
2012-04-23 22:56:37 +03:00
case Obj : : FAVORABLE_WINDS :
2009-07-01 18:58:20 +03:00
return 21 ;
2012-04-23 22:56:37 +03:00
case Obj : : FIERY_FIELDS :
2009-07-01 18:58:20 +03:00
return 14 ;
2012-04-23 22:56:37 +03:00
case Obj : : HOLY_GROUNDS :
2009-07-01 18:58:20 +03:00
return 18 ;
2012-04-23 22:56:37 +03:00
case Obj : : LUCID_POOLS :
2009-07-01 18:58:20 +03:00
return 17 ;
2012-04-23 22:56:37 +03:00
case Obj : : MAGIC_CLOUDS :
2009-07-01 18:58:20 +03:00
return 16 ;
2012-04-23 22:56:37 +03:00
case Obj : : MAGIC_PLAINS1 : case Obj : : MAGIC_PLAINS2 :
2009-07-01 18:58:20 +03:00
return 9 ;
2012-04-23 22:56:37 +03:00
case Obj : : ROCKLANDS :
2009-07-01 18:58:20 +03:00
return 15 ;
}
}
2009-02-14 15:49:30 +02:00
2012-04-08 05:29:11 +03:00
if ( ! t . isWater ( ) & & t . isCoastal ( ) )
return 1 ; //sand/beach
2010-07-31 03:26:34 +03:00
switch ( t . tertype )
2009-02-10 16:21:51 +02:00
{
2009-05-07 20:20:41 +03:00
case TerrainTile : : dirt :
2009-02-10 16:21:51 +02:00
return rand ( ) % 3 + 3 ;
2009-05-07 20:20:41 +03:00
case TerrainTile : : sand :
2009-02-10 16:21:51 +02:00
return 2 ; //TODO: coast support
2009-05-07 20:20:41 +03:00
case TerrainTile : : grass :
2009-02-10 16:21:51 +02:00
return rand ( ) % 2 + 6 ;
2009-05-07 20:20:41 +03:00
case TerrainTile : : snow :
2009-02-10 16:21:51 +02:00
return rand ( ) % 2 + 10 ;
2009-05-07 20:20:41 +03:00
case TerrainTile : : swamp :
2009-02-10 16:21:51 +02:00
return 13 ;
2009-05-07 20:20:41 +03:00
case TerrainTile : : rough :
2009-02-10 16:21:51 +02:00
return 23 ;
2009-05-07 20:20:41 +03:00
case TerrainTile : : subterranean :
2009-02-10 16:21:51 +02:00
return 12 ;
2009-05-07 20:20:41 +03:00
case TerrainTile : : lava :
2009-02-10 16:21:51 +02:00
return 8 ;
2009-05-07 20:20:41 +03:00
case TerrainTile : : water :
2009-02-10 16:21:51 +02:00
return 25 ;
2009-05-07 20:20:41 +03:00
case TerrainTile : : rock :
2009-02-10 16:21:51 +02:00
return 15 ;
default :
return - 1 ;
}
2009-02-09 16:50:32 +02:00
}
2012-04-23 22:56:37 +03:00
2010-07-15 06:04:57 +03:00
std : : set < std : : pair < int , int > > costDiff ( const std : : vector < ui32 > & a , const std : : vector < ui32 > & b , const int modifier = 100 ) //modifer %
{
std : : set < std : : pair < int , int > > ret ;
2011-12-14 00:23:17 +03:00
for ( int j = 0 ; j < GameConstants : : RESOURCE_QUANTITY ; j + + )
2010-07-15 06:04:57 +03:00
{
assert ( a [ j ] > = b [ j ] ) ;
if ( int dif = modifier * ( a [ j ] - b [ j ] ) / 100 )
ret . insert ( std : : make_pair ( j , dif ) ) ;
}
return ret ;
}
UpgradeInfo CGameState : : getUpgradeInfo ( const CStackInstance & stack )
2008-08-15 15:11:42 +03:00
{
UpgradeInfo ret ;
2010-07-15 06:04:57 +03:00
const CCreature * base = stack . type ;
2011-12-14 00:23:17 +03:00
const CGHeroInstance * h = stack . armyObj - > ID = = GameConstants : : HEROI_TYPE ? static_cast < const CGHeroInstance * > ( stack . armyObj ) : NULL ;
2010-07-15 06:04:57 +03:00
const CGTownInstance * t = NULL ;
2011-12-14 00:23:17 +03:00
if ( stack . armyObj - > ID = = GameConstants : : TOWNI_TYPE )
2010-07-15 06:04:57 +03:00
t = static_cast < const CGTownInstance * > ( stack . armyObj ) ;
else if ( h )
2010-08-15 10:39:07 +03:00
{ //hero speciality
2011-09-06 16:59:26 +03:00
TBonusListPtr lista = h - > speciality . getBonuses ( Selector : : typeSubtype ( Bonus : : SPECIAL_UPGRADE , base - > idNumber ) ) ;
2011-06-25 16:53:15 +03:00
BOOST_FOREACH ( const Bonus * it , * lista )
2010-07-17 09:49:16 +03:00
{
ui16 nid = it - > additionalInfo ;
2011-07-05 09:14:07 +03:00
if ( nid ! = base - > idNumber ) //in very specific case the upgrade is available by default (?)
2010-07-17 09:49:16 +03:00
{
ret . newID . push_back ( nid ) ;
2011-07-05 09:14:07 +03:00
ret . cost . push_back ( VLC - > creh - > creatures [ nid ] - > cost - base - > cost ) ;
2010-07-17 09:49:16 +03:00
}
}
2010-07-15 06:04:57 +03:00
t = h - > visitedTown ;
2010-07-17 09:49:16 +03:00
}
2010-07-15 06:04:57 +03:00
if ( t )
2008-08-15 15:11:42 +03:00
{
2012-01-13 17:18:32 +03:00
BOOST_FOREACH ( const CGTownInstance : : TCreaturesSet : : value_type & dwelling , t - > creatures )
2008-08-15 15:11:42 +03:00
{
2012-01-13 17:18:32 +03:00
if ( vstd : : contains ( dwelling . second , base - > idNumber ) ) //Dwelling with our creature
2008-08-15 15:11:42 +03:00
{
2012-01-13 17:18:32 +03:00
BOOST_FOREACH ( ui32 upgrID , dwelling . second )
2008-08-15 15:11:42 +03:00
{
2012-01-13 17:18:32 +03:00
if ( vstd : : contains ( base - > upgrades , upgrID ) ) //possible upgrade
{
ret . newID . push_back ( upgrID ) ;
ret . cost . push_back ( VLC - > creh - > creatures [ upgrID ] - > cost - base - > cost ) ;
}
2008-08-15 15:11:42 +03:00
}
}
2010-07-15 06:04:57 +03:00
}
}
//hero is visiting Hill Fort
2012-02-16 20:10:58 +03:00
if ( h & & map - > getTile ( h - > visitablePos ( ) ) . visitableObjects . front ( ) - > ID = = 35 )
2010-07-15 06:04:57 +03:00
{
static const int costModifiers [ ] = { 0 , 25 , 50 , 75 , 100 } ; //we get cheaper upgrades depending on level
const int costModifier = costModifiers [ std : : min < int > ( std : : max ( ( int ) base - > level - 1 , 0 ) , ARRAY_COUNT ( costModifiers ) - 1 ) ] ;
BOOST_FOREACH ( si32 nid , base - > upgrades )
{
ret . newID . push_back ( nid ) ;
2011-07-05 09:14:07 +03:00
ret . cost . push_back ( ( VLC - > creh - > creatures [ nid ] - > cost - base - > cost ) * costModifier / 100 ) ;
2010-07-15 06:04:57 +03:00
}
2008-08-15 15:11:42 +03:00
}
2010-07-15 06:04:57 +03:00
2008-08-15 15:11:42 +03:00
if ( ret . newID . size ( ) )
ret . oldID = base - > idNumber ;
return ret ;
}
2008-09-07 06:38:37 +03:00
2010-08-13 13:46:08 +03:00
int CGameState : : getPlayerRelations ( ui8 color1 , ui8 color2 )
{
if ( color1 = = color2 )
return 2 ;
2012-01-03 04:55:26 +03:00
if ( color1 = = 255 | | color2 = = 255 ) //neutral player has no friends
2012-02-16 20:10:58 +03:00
return 0 ;
2012-01-03 04:55:26 +03:00
2010-08-13 13:46:08 +03:00
const TeamState * ts = getPlayerTeam ( color1 ) ;
if ( ts & & vstd : : contains ( ts - > players , color2 ) )
return 1 ;
return 0 ;
}
2008-11-28 03:36:34 +02:00
void CGameState : : loadTownDInfos ( )
{
2011-09-04 03:04:48 +03:00
int i ;
2011-12-14 00:23:17 +03:00
const JsonNode config ( GameConstants : : DATA_DIR + " /config/towns_defs.json " ) ;
2011-09-04 21:07:26 +03:00
2011-12-14 00:23:17 +03:00
assert ( config [ " town_defnames " ] . Vector ( ) . size ( ) = = GameConstants : : F_NUMBER ) ;
2011-09-04 21:07:26 +03:00
i = 0 ;
BOOST_FOREACH ( const JsonNode & t , config [ " town_defnames " ] . Vector ( ) )
{
2008-11-28 03:36:34 +02:00
villages [ i ] = new CGDefInfo ( * VLC - > dobjinfo - > castles [ i ] ) ;
2011-09-04 21:07:26 +03:00
villages [ i ] - > name = t [ " village " ] . String ( ) ;
map - > defy . push_back ( villages [ i ] ) ;
2008-11-28 03:36:34 +02:00
forts [ i ] = VLC - > dobjinfo - > castles [ i ] ;
2010-08-01 17:04:48 +03:00
map - > defy . push_back ( forts [ i ] ) ;
2011-09-04 21:07:26 +03:00
capitols [ i ] = new CGDefInfo ( * VLC - > dobjinfo - > castles [ i ] ) ;
2011-09-04 03:04:48 +03:00
capitols [ i ] - > name = t [ " capitol " ] . String ( ) ;
2011-09-04 21:07:26 +03:00
map - > defy . push_back ( capitols [ i ] ) ;
2012-02-16 20:10:58 +03:00
2011-09-04 21:07:26 +03:00
+ + i ;
2011-09-04 03:04:48 +03:00
}
2008-11-28 03:36:34 +02:00
}
2008-12-27 03:01:59 +02:00
2010-07-10 05:15:49 +03:00
void CGameState : : getNeighbours ( const TerrainTile & srct , int3 tile , std : : vector < int3 > & vec , const boost : : logic : : tribool & onLand , bool limitCoastSailing )
2009-02-12 16:44:58 +02:00
{
2011-09-19 23:50:25 +03:00
static const int3 dirs [ ] = { int3 ( 0 , 1 , 0 ) , int3 ( 0 , - 1 , 0 ) , int3 ( - 1 , 0 , 0 ) , int3 ( + 1 , 0 , 0 ) ,
2009-07-19 04:00:19 +03:00
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 + + )
2009-02-12 16:44:58 +02:00
{
2009-08-30 15:47:40 +03:00
const int3 hlp = tile + dirs [ i ] ;
2012-02-16 20:10:58 +03:00
if ( ! map - > isInTheMap ( hlp ) )
2009-07-19 04:00:19 +03:00
continue ;
2009-08-30 15:47:40 +03:00
const TerrainTile & hlpt = map - > getTile ( hlp ) ;
2011-09-19 23:50:25 +03:00
// //we cannot visit things from blocked tiles
// if(srct.blocked && !srct.visitable && hlpt.visitable && srct.blockingObjects.front()->ID != HEROI_TYPE)
// {
// continue;
// }
2010-05-16 16:42:19 +03:00
2010-07-10 05:15:49 +03:00
if ( srct . tertype = = TerrainTile : : water & & limitCoastSailing & & hlpt . tertype = = TerrainTile : : water & & dirs [ i ] . x & & dirs [ i ] . y ) //diagonal move through water
{
int3 hlp1 = tile ,
hlp2 = tile ;
hlp1 . x + = dirs [ i ] . x ;
hlp2 . y + = dirs [ i ] . y ;
if ( map - > getTile ( hlp1 ) . tertype ! = TerrainTile : : water | | map - > getTile ( hlp2 ) . tertype ! = TerrainTile : : water )
continue ;
}
2012-02-16 20:10:58 +03:00
if ( ( indeterminate ( onLand ) | | onLand = = ( hlpt . tertype ! = TerrainTile : : water ) )
& & hlpt . tertype ! = TerrainTile : : rock )
2009-07-19 04:00:19 +03:00
{
2009-02-12 16:44:58 +02:00
vec . push_back ( hlp ) ;
2009-07-19 04:00:19 +03:00
}
2009-02-12 16:44:58 +02:00
}
}
2009-08-30 15:47:40 +03:00
int CGameState : : getMovementCost ( const CGHeroInstance * h , const int3 & src , const int3 & dest , int remainingMovePoints , bool checkLast )
2009-02-12 16:44:58 +02:00
{
2009-03-27 01:05:40 +02:00
if ( src = = dest ) //same tile
return 0 ;
2009-02-12 16:44:58 +02:00
TerrainTile & s = map - > terrain [ src . x ] [ src . y ] [ src . z ] ,
& d = map - > terrain [ dest . x ] [ dest . y ] [ dest . z ] ;
//get basic cost
int ret = h - > getTileCost ( d , s ) ;
2010-05-31 23:38:14 +03:00
if ( d . blocked & & h - > hasBonusOfType ( Bonus : : FLYING_MOVEMENT ) )
2010-05-15 18:00:19 +03:00
{
2011-06-24 20:43:02 +03:00
bool freeFlying = h - > getBonusesCount ( Selector : : typeSubtype ( Bonus : : FLYING_MOVEMENT , 1 ) ) > 0 ;
2010-05-15 18:00:19 +03:00
if ( ! freeFlying )
{
2011-12-14 00:23:17 +03:00
ret * = 1.4 ; //40% penalty for movement over blocked tile
2010-05-15 18:00:19 +03:00
}
}
else if ( d . tertype = = TerrainTile : : water )
{
2011-09-19 23:50:25 +03:00
if ( h - > boat & & s . hasFavourableWinds ( ) & & d . hasFavourableWinds ( ) ) //Favourable Winds
2011-12-14 00:23:17 +03:00
ret * = 0.666 ;
2011-06-24 20:43:02 +03:00
else if ( ! h - > boat & & h - > getBonusesCount ( Selector : : typeSubtype ( Bonus : : WATER_WALKING , 1 ) ) > 0 )
2011-12-14 00:23:17 +03:00
ret * = 1.4 ; //40% penalty for water walking
2010-05-15 18:00:19 +03:00
}
2009-08-28 12:03:58 +03:00
if ( src . x ! = dest . x & & src . y ! = dest . y ) //it's diagonal move
2009-02-12 16:44:58 +02:00
{
int old = ret ;
2009-08-28 12:03:58 +03:00
ret * = 1.414213 ;
2009-07-19 04:00:19 +03:00
//diagonal move costs too much but normal move is possible - allow diagonal move for remaining move points
2009-08-30 15:47:40 +03:00
if ( ret > remainingMovePoints & & remainingMovePoints > = old )
2009-02-12 16:44:58 +02:00
{
return remainingMovePoints ;
}
}
int left = remainingMovePoints - ret ;
if ( checkLast & & left > 0 & & remainingMovePoints - ret < 250 ) //it might be the last tile - if no further move possible we take all move points
{
std : : vector < int3 > vec ;
2010-07-10 05:15:49 +03:00
getNeighbours ( d , dest , vec , s . tertype ! = TerrainTile : : water , true ) ;
2009-02-12 16:44:58 +02:00
for ( size_t i = 0 ; i < vec . size ( ) ; i + + )
{
int fcost = getMovementCost ( h , dest , vec [ i ] , left , false ) ;
if ( fcost < = left )
{
return ret ;
}
}
ret = remainingMovePoints ;
}
return ret ;
}
2009-12-30 09:49:25 +02:00
2009-03-07 00:25:19 +02:00
void CGameState : : apply ( CPack * pack )
{
2009-08-04 02:53:18 +03:00
ui16 typ = typeList . getTypeID ( pack ) ;
applierGs - > apps [ typ ] - > applyOnGS ( this , pack ) ;
2009-03-07 00:25:19 +02:00
}
2009-06-11 20:21:06 +03:00
bool CGameState : : getPath ( int3 src , int3 dest , const CGHeroInstance * hero , CPath & ret )
2009-03-19 16:17:19 +02:00
{
2011-09-19 23:50:25 +03:00
//the old pathfinder is not supported anymore!
assert ( 0 ) ;
return false ;
2009-03-19 16:17:19 +02:00
}
2009-08-30 15:47:40 +03:00
void CGameState : : calculatePaths ( const CGHeroInstance * hero , CPathsInfo & out , int3 src , int movement )
{
2011-09-19 23:50:25 +03:00
CPathfinder pathfinder ( out , this , hero ) ;
pathfinder . calculatePaths ( src , movement ) ;
2009-08-30 15:47:40 +03:00
}
2009-08-28 12:03:58 +03:00
2010-05-06 15:13:31 +03:00
/**
* Tells if the tile is guarded by a monster as well as the position
* of the monster that will attack on it .
*
* @ return int3 ( - 1 , - 1 , - 1 ) if the tile is unguarded , or the position of
* the monster guarding the tile .
*/
int3 CGameState : : guardingCreaturePosition ( int3 pos ) const
{
2010-05-27 00:59:58 +03:00
const int3 originalPos = pos ;
2010-05-06 15:13:31 +03:00
// Give monster at position priority.
if ( ! map - > isInTheMap ( pos ) )
return int3 ( - 1 , - 1 , - 1 ) ;
const TerrainTile & posTile = map - > terrain [ pos . x ] [ pos . y ] [ pos . z ] ;
2012-02-16 20:10:58 +03:00
if ( posTile . visitable )
2010-05-27 00:59:58 +03:00
{
2012-02-16 20:10:58 +03:00
BOOST_FOREACH ( CGObjectInstance * obj , posTile . visitableObjects )
2010-05-27 00:59:58 +03:00
{
if ( obj - > blockVisit )
{
if ( obj - > ID = = 54 ) // Monster
return pos ;
else
return int3 ( - 1 , - 1 , - 1 ) ; //blockvis objects are not guarded by neighbouring creatures
2010-05-06 15:13:31 +03:00
}
}
}
// See if there are any monsters adjacent.
pos - = int3 ( 1 , 1 , 0 ) ; // Start with top left.
2012-02-16 20:10:58 +03:00
for ( int dx = 0 ; dx < 3 ; dx + + )
2010-05-27 00:59:58 +03:00
{
2012-02-16 20:10:58 +03:00
for ( int dy = 0 ; dy < 3 ; dy + + )
2010-05-27 00:59:58 +03:00
{
2012-02-16 20:10:58 +03:00
if ( map - > isInTheMap ( pos ) )
2010-05-27 00:59:58 +03:00
{
2010-05-06 15:13:31 +03:00
TerrainTile & tile = map - > terrain [ pos . x ] [ pos . y ] [ pos . z ] ;
2012-02-16 20:10:58 +03:00
if ( tile . visitable & & ( tile . tertype = = TerrainTile : : water ) = = ( posTile . tertype = = TerrainTile : : water ) )
2010-05-27 00:59:58 +03:00
{
2012-02-16 20:10:58 +03:00
BOOST_FOREACH ( CGObjectInstance * obj , tile . visitableObjects )
2010-05-27 00:59:58 +03:00
{
if ( obj - > ID = = 54 & & checkForVisitableDir ( pos , & map - > getTile ( originalPos ) , originalPos ) ) // Monster being able to attack investigated tile
2012-02-16 20:10:58 +03:00
{
2010-05-06 15:13:31 +03:00
return pos ;
}
}
}
}
pos . y + + ;
}
pos . y - = 3 ;
pos . x + + ;
}
return int3 ( - 1 , - 1 , - 1 ) ;
}
2009-07-30 15:49:45 +03:00
bool CGameState : : isVisible ( int3 pos , int player )
{
2009-07-31 14:20:53 +03:00
if ( player = = 255 ) //neutral player
return false ;
2010-08-03 15:34:06 +03:00
return getPlayerTeam ( player ) - > fogOfWarMap [ pos . x ] [ pos . y ] [ pos . z ] ;
2009-07-30 15:49:45 +03:00
}
bool CGameState : : isVisible ( const CGObjectInstance * obj , int player )
{
2011-05-03 06:14:18 +03:00
if ( player = = - 1 )
return true ;
if ( player = = 255 ) //neutral player -> TODO ??? needed?
2009-07-31 14:20:53 +03:00
return false ;
2009-07-30 15:49:45 +03:00
//object is visible when at least one blocked tile is visible
for ( int fx = 0 ; fx < 8 ; + + fx )
{
for ( int fy = 0 ; fy < 6 ; + + fy )
{
2010-12-25 21:23:30 +02:00
int3 pos = obj - > pos + int3 ( fx - 7 , fy - 5 , 0 ) ;
2012-02-16 20:10:58 +03:00
if ( map - > isInTheMap ( pos )
& & ! ( ( obj - > defInfo - > blockMap [ fy ] > > ( 7 - fx ) ) & 1 )
2010-12-25 21:23:30 +02:00
& & isVisible ( pos , player ) )
return true ;
2010-02-23 17:39:31 +02:00
}
2009-08-23 16:41:57 +03:00
}
2010-12-25 21:23:30 +02:00
return false ;
2009-08-23 16:41:57 +03:00
}
2010-12-25 21:23:30 +02:00
bool CGameState : : checkForVisitableDir ( const int3 & src , const int3 & dst ) const
2009-09-01 16:54:13 +03:00
{
2010-12-25 21:23:30 +02:00
const TerrainTile * pom = & map - > getTile ( dst ) ;
return checkForVisitableDir ( src , pom , dst ) ;
2009-09-01 16:54:13 +03:00
}
2010-12-25 21:23:30 +02:00
bool CGameState : : checkForVisitableDir ( const int3 & src , const TerrainTile * pom , const int3 & dst ) const
2010-04-06 16:19:54 +03:00
{
2011-12-14 00:23:17 +03:00
for ( ui32 b = 0 ; b < pom - > visitableObjects . size ( ) ; + + b ) //checking destination tile
2009-09-02 17:10:19 +03:00
{
2010-12-25 21:23:30 +02:00
if ( ! vstd : : contains ( pom - > blockingObjects , pom - > visitableObjects [ b ] ) ) //this visitable object is not blocking, ignore
2009-09-02 17:10:19 +03:00
continue ;
2010-12-25 21:23:30 +02:00
CGDefInfo * di = pom - > visitableObjects [ b ] - > defInfo ;
if ( ( dst . x = = src . x - 1 & & dst . y = = src . y - 1 ) & & ! ( di - > visitDir & ( 1 < < 4 ) ) )
2009-09-02 17:10:19 +03:00
{
2010-12-25 21:23:30 +02:00
return false ;
2009-09-02 17:10:19 +03:00
}
2010-12-25 21:23:30 +02:00
if ( ( dst . x = = src . x & & dst . y = = src . y - 1 ) & & ! ( di - > visitDir & ( 1 < < 5 ) ) )
2009-09-02 17:10:19 +03:00
{
2010-12-25 21:23:30 +02:00
return false ;
2009-09-02 17:10:19 +03:00
}
2010-12-25 21:23:30 +02:00
if ( ( dst . x = = src . x + 1 & & dst . y = = src . y - 1 ) & & ! ( di - > visitDir & ( 1 < < 6 ) ) )
2009-11-08 16:44:58 +02:00
{
2010-12-25 21:23:30 +02:00
return false ;
2009-11-08 16:44:58 +02:00
}
2010-12-25 21:23:30 +02:00
if ( ( dst . x = = src . x + 1 & & dst . y = = src . y ) & & ! ( di - > visitDir & ( 1 < < 7 ) ) )
2009-11-08 16:44:58 +02:00
{
2010-12-25 21:23:30 +02:00
return false ;
2009-11-08 16:44:58 +02:00
}
2010-12-25 21:23:30 +02:00
if ( ( dst . x = = src . x + 1 & & dst . y = = src . y + 1 ) & & ! ( di - > visitDir & ( 1 < < 0 ) ) )
2009-11-08 16:44:58 +02:00
{
2010-12-25 21:23:30 +02:00
return false ;
2009-11-08 16:44:58 +02:00
}
2010-12-25 21:23:30 +02:00
if ( ( dst . x = = src . x & & dst . y = = src . y + 1 ) & & ! ( di - > visitDir & ( 1 < < 1 ) ) )
2009-11-08 16:44:58 +02:00
{
2010-12-25 21:23:30 +02:00
return false ;
2009-11-08 16:44:58 +02:00
}
2010-12-25 21:23:30 +02:00
if ( ( dst . x = = src . x - 1 & & dst . y = = src . y + 1 ) & & ! ( di - > visitDir & ( 1 < < 2 ) ) )
2009-11-08 16:44:58 +02:00
{
2010-12-25 21:23:30 +02:00
return false ;
2009-11-08 16:44:58 +02:00
}
2010-12-25 21:23:30 +02:00
if ( ( dst . x = = src . x - 1 & & dst . y = = src . y ) & & ! ( di - > visitDir & ( 1 < < 3 ) ) )
2009-11-08 16:44:58 +02:00
{
2010-12-25 21:23:30 +02:00
return false ;
2009-11-08 16:44:58 +02:00
}
}
2010-12-25 21:23:30 +02:00
return true ;
2009-11-08 16:44:58 +02:00
}
2010-08-29 21:29:00 +03:00
2009-09-04 17:11:42 +03:00
2010-01-29 22:52:45 +02:00
int CGameState : : victoryCheck ( ui8 player ) const
{
2011-05-10 01:20:47 +03:00
const PlayerState * p = CGameInfoCallback : : getPlayer ( player ) ;
2012-01-03 04:55:26 +03:00
if ( map - > victoryCondition . condition = = EVictoryConditionType : : WINSTANDARD | | map - > victoryCondition . allowNormalVictory
| | ( ! p - > human & & ! map - > victoryCondition . appliesToAI ) ) //if the special victory condition applies only to human, AI has the standard)
{
2010-01-29 22:52:45 +02:00
if ( player = = checkForStandardWin ( ) )
return - 1 ;
2012-01-03 04:55:26 +03:00
}
2010-01-29 22:52:45 +02:00
2010-07-30 14:29:42 +03:00
if ( p - > enteredWinningCheatCode )
{ //cheater or tester, but has entered the code...
return 1 ;
}
2010-01-29 22:52:45 +02:00
if ( p - > human | | map - > victoryCondition . appliesToAI )
{
switch ( map - > victoryCondition . condition )
{
2011-12-14 00:23:17 +03:00
case EVictoryConditionType : : ARTIFACT :
2010-01-29 22:52:45 +02:00
//check if any hero has winning artifact
for ( size_t i = 0 ; i < p - > heroes . size ( ) ; i + + )
if ( p - > heroes [ i ] - > hasArt ( map - > victoryCondition . ID ) )
return 1 ;
break ;
2011-12-14 00:23:17 +03:00
case EVictoryConditionType : : GATHERTROOP :
2010-01-29 22:52:45 +02:00
{
//check if in players armies there is enough creatures
int total = 0 ; //creature counter
for ( size_t i = 0 ; i < map - > objects . size ( ) ; i + + )
{
const CArmedInstance * ai = NULL ;
2012-02-16 20:10:58 +03:00
if ( map - > objects [ i ]
2010-01-30 14:46:15 +02:00
& & map - > objects [ i ] - > tempOwner = = player //object controlled by player
2010-12-19 00:11:28 +02:00
& & ( ai = dynamic_cast < const CArmedInstance * > ( map - > objects [ i ] . get ( ) ) ) ) //contains army
2010-01-29 22:52:45 +02:00
{
2010-05-02 21:20:26 +03:00
for ( TSlots : : const_iterator i = ai - > Slots ( ) . begin ( ) ; i ! = ai - > Slots ( ) . end ( ) ; + + i ) //iterate through army
2010-11-22 02:34:46 +02:00
if ( i - > second - > type - > idNumber = = map - > victoryCondition . ID ) //it's searched creature
total + = i - > second - > count ;
2010-01-29 22:52:45 +02:00
}
}
if ( total > = map - > victoryCondition . count )
return 1 ;
}
break ;
2011-12-14 00:23:17 +03:00
case EVictoryConditionType : : GATHERRESOURCE :
2010-01-29 22:52:45 +02:00
if ( p - > resources [ map - > victoryCondition . ID ] > = map - > victoryCondition . count )
return 1 ;
break ;
2011-12-14 00:23:17 +03:00
case EVictoryConditionType : : BUILDCITY :
2010-01-30 14:46:15 +02:00
{
const CGTownInstance * t = static_cast < const CGTownInstance * > ( map - > victoryCondition . obj ) ;
if ( t - > tempOwner = = player & & t - > fortLevel ( ) - 1 > = map - > victoryCondition . ID & & t - > hallLevel ( ) - 1 > = map - > victoryCondition . count )
2010-01-29 22:52:45 +02:00
return 1 ;
2010-01-30 14:46:15 +02:00
}
2010-01-29 22:52:45 +02:00
break ;
2011-12-14 00:23:17 +03:00
case EVictoryConditionType : : BUILDGRAIL :
2010-05-14 05:18:37 +03:00
BOOST_FOREACH ( const CGTownInstance * t , map - > towns )
if ( ( t = = map - > victoryCondition . obj | | ! map - > victoryCondition . obj )
2012-02-16 20:10:58 +03:00
& & t - > tempOwner = = player
2012-03-29 00:54:43 +03:00
& & vstd : : contains ( t - > builtBuildings , EBuilding : : GRAIL ) )
2010-01-29 22:52:45 +02:00
return 1 ;
break ;
2011-12-14 00:23:17 +03:00
case EVictoryConditionType : : BEATHERO :
if ( map - > victoryCondition . obj - > tempOwner > = GameConstants : : PLAYER_LIMIT ) //target hero not present on map
2010-01-29 22:52:45 +02:00
return 1 ;
break ;
2011-12-14 00:23:17 +03:00
case EVictoryConditionType : : CAPTURECITY :
2010-01-29 22:52:45 +02:00
{
if ( map - > victoryCondition . obj - > tempOwner = = player )
return 1 ;
}
break ;
2011-12-14 00:23:17 +03:00
case EVictoryConditionType : : BEATMONSTER :
2010-01-29 22:52:45 +02:00
if ( ! map - > objects [ map - > victoryCondition . obj - > id ] ) //target monster not present on map
return 1 ;
break ;
2011-12-14 00:23:17 +03:00
case EVictoryConditionType : : TAKEDWELLINGS :
2010-01-29 22:52:45 +02:00
for ( size_t i = 0 ; i < map - > objects . size ( ) ; i + + )
{
if ( map - > objects [ i ] & & map - > objects [ i ] - > tempOwner ! = player ) //check not flagged objs
{
switch ( map - > objects [ i ] - > ID )
{
case 17 : case 18 : case 19 : case 20 : //dwellings
case 216 : case 217 : case 218 :
return 0 ; //found not flagged dwelling - player not won
}
}
}
return 1 ;
break ;
2011-12-14 00:23:17 +03:00
case EVictoryConditionType : : TAKEMINES :
2010-01-29 22:52:45 +02:00
for ( size_t i = 0 ; i < map - > objects . size ( ) ; i + + )
{
if ( map - > objects [ i ] & & map - > objects [ i ] - > tempOwner ! = player ) //check not flagged objs
{
switch ( map - > objects [ i ] - > ID )
{
case 53 : case 220 :
return 0 ; //found not flagged mine - player not won
}
}
}
return 1 ;
break ;
2011-12-14 00:23:17 +03:00
case EVictoryConditionType : : TRANSPORTITEM :
2010-01-30 14:46:15 +02:00
{
const CGTownInstance * t = static_cast < const CGTownInstance * > ( map - > victoryCondition . obj ) ;
2010-11-09 13:27:58 +02:00
if ( ( t - > visitingHero & & t - > visitingHero - > hasArt ( map - > victoryCondition . ID ) )
| | ( t - > garrisonHero & & t - > garrisonHero - > hasArt ( map - > victoryCondition . ID ) ) )
2010-01-30 14:46:15 +02:00
{
return 1 ;
}
}
2010-01-29 22:52:45 +02:00
break ;
}
}
return 0 ;
}
ui8 CGameState : : checkForStandardWin ( ) const
{
//std victory condition is:
//all enemies lost
ui8 supposedWinner = 255 , winnerTeam = 255 ;
for ( std : : map < ui8 , PlayerState > : : const_iterator i = players . begin ( ) ; i ! = players . end ( ) ; i + + )
{
2011-12-14 00:23:17 +03:00
if ( i - > second . status = = PlayerState : : INGAME & & i - > first < GameConstants : : PLAYER_LIMIT )
2010-01-29 22:52:45 +02:00
{
2012-02-16 20:10:58 +03:00
if ( supposedWinner = = 255 )
2010-01-29 22:52:45 +02:00
{
//first player remaining ingame - candidate for victory
supposedWinner = i - > second . color ;
2010-08-03 15:34:06 +03:00
winnerTeam = i - > second . team ;
2010-01-29 22:52:45 +02:00
}
2010-08-03 15:34:06 +03:00
else if ( winnerTeam ! = i - > second . team )
2010-01-29 22:52:45 +02:00
{
//current candidate has enemy remaining in game -> no vicotry
return 255 ;
}
}
}
return supposedWinner ;
}
bool CGameState : : checkForStandardLoss ( ui8 player ) const
{
//std loss condition is: player lost all towns and heroes
2011-05-10 01:20:47 +03:00
const PlayerState & p = * CGameInfoCallback : : getPlayer ( player ) ;
2010-01-30 17:00:05 +02:00
return ! p . heroes . size ( ) & & ! p . towns . size ( ) ;
2010-01-29 22:52:45 +02:00
}
2010-02-11 21:18:30 +02:00
struct statsHLP
2010-02-01 19:51:33 +02:00
{
2010-02-11 21:18:30 +02:00
typedef std : : pair < ui8 , si64 > TStat ;
//converts [<player's color, value>] to vec[place] -> platers
static std : : vector < std : : list < ui8 > > getRank ( std : : vector < TStat > stats )
2010-02-01 19:51:33 +02:00
{
2010-02-11 21:18:30 +02:00
std : : sort ( stats . begin ( ) , stats . end ( ) , statsHLP ( ) ) ;
2010-02-01 19:51:33 +02:00
2010-02-11 21:18:30 +02:00
//put first element
std : : vector < std : : list < ui8 > > ret ;
std : : list < ui8 > tmp ;
tmp . push_back ( stats [ 0 ] . first ) ;
ret . push_back ( tmp ) ;
2010-02-01 19:51:33 +02:00
2010-02-11 21:18:30 +02:00
//the rest of elements
for ( int g = 1 ; g < stats . size ( ) ; + + g )
{
if ( stats [ g ] . second = = stats [ g - 1 ] . second )
2010-02-01 19:51:33 +02:00
{
2010-02-11 21:18:30 +02:00
( ret . end ( ) - 1 ) - > push_back ( stats [ g ] . first ) ;
}
else
{
//create next occupied rank
std : : list < ui8 > tmp ;
tmp . push_back ( stats [ g ] . first ) ;
ret . push_back ( tmp ) ;
2010-02-01 19:51:33 +02:00
}
}
2010-02-11 21:18:30 +02:00
return ret ;
}
2010-02-06 15:49:14 +02:00
2010-02-11 21:18:30 +02:00
bool operator ( ) ( const TStat & a , const TStat & b ) const
{
return a . second > b . second ;
}
static const CGHeroInstance * findBestHero ( CGameState * gs , int color )
{
2010-12-20 15:04:24 +02:00
std : : vector < ConstTransitivePtr < CGHeroInstance > > & h = gs - > players [ color ] . heroes ;
2010-02-28 14:39:38 +02:00
if ( ! h . size ( ) )
return NULL ;
2010-02-11 21:18:30 +02:00
//best hero will be that with highest exp
int best = 0 ;
2010-02-28 14:39:38 +02:00
for ( int b = 1 ; b < h . size ( ) ; + + b )
2010-02-06 15:49:14 +02:00
{
2010-02-28 14:39:38 +02:00
if ( h [ b ] - > exp > h [ best ] - > exp )
2010-02-06 15:49:14 +02:00
{
2010-02-11 21:18:30 +02:00
best = b ;
2010-02-06 15:49:14 +02:00
}
}
2010-02-28 14:39:38 +02:00
return h [ best ] ;
2010-02-11 21:18:30 +02:00
}
2010-02-06 15:49:14 +02:00
2010-02-11 21:18:30 +02:00
//calculates total number of artifacts that belong to given player
static int getNumberOfArts ( const PlayerState * ps )
{
int ret = 0 ;
for ( int g = 0 ; g < ps - > heroes . size ( ) ; + + g )
2010-02-06 15:49:14 +02:00
{
2011-01-18 20:56:14 +02:00
ret + = ps - > heroes [ g ] - > artifactsInBackpack . size ( ) + ps - > heroes [ g ] - > artifactsWorn . size ( ) ;
2010-02-06 15:49:14 +02:00
}
2010-02-11 21:18:30 +02:00
return ret ;
}
} ;
2010-02-01 19:51:33 +02:00
2010-02-11 21:18:30 +02:00
void CGameState : : obtainPlayersStats ( SThievesGuildInfo & tgi , int level )
{
2010-02-01 19:51:33 +02:00
# define FILL_FIELD(FIELD, VAL_GETTER) \
{ \
std : : vector < std : : pair < ui8 , si64 > > stats ; \
for ( std : : map < ui8 , PlayerState > : : const_iterator g = players . begin ( ) ; g ! = players . end ( ) ; + + g ) \
{ \
if ( g - > second . color = = 255 ) \
continue ; \
std : : pair < ui8 , si64 > stat ; \
stat . first = g - > second . color ; \
stat . second = VAL_GETTER ; \
stats . push_back ( stat ) ; \
} \
2010-02-11 21:18:30 +02:00
tgi . FIELD = statsHLP : : getRank ( stats ) ; \
2010-02-01 19:51:33 +02:00
}
for ( std : : map < ui8 , PlayerState > : : const_iterator g = players . begin ( ) ; g ! = players . end ( ) ; + + g )
{
if ( g - > second . color ! = 255 )
tgi . playerColors . push_back ( g - > second . color ) ;
}
2012-02-16 20:10:58 +03:00
2010-02-01 19:51:33 +02:00
if ( level > = 1 ) //num of towns & num of heroes
{
//num of towns
FILL_FIELD ( numOfTowns , g - > second . towns . size ( ) )
//num of heroes
FILL_FIELD ( numOfHeroes , g - > second . heroes . size ( ) )
2010-02-04 20:40:40 +02:00
//best hero's portrait
for ( std : : map < ui8 , PlayerState > : : const_iterator g = players . begin ( ) ; g ! = players . end ( ) ; + + g )
{
if ( g - > second . color = = 255 )
continue ;
2010-02-11 21:18:30 +02:00
const CGHeroInstance * best = statsHLP : : findBestHero ( this , g - > second . color ) ;
2010-02-07 17:06:14 +02:00
InfoAboutHero iah ;
iah . initFromHero ( best , level > = 8 ) ;
2010-05-02 21:20:26 +03:00
iah . army . clear ( ) ;
2010-02-04 20:40:40 +02:00
tgi . colorToBestHero [ g - > second . color ] = iah ;
}
2010-02-01 19:51:33 +02:00
}
if ( level > = 2 ) //gold
{
2011-07-05 09:14:07 +03:00
FILL_FIELD ( gold , g - > second . resources [ Res : : GOLD ] )
2010-02-01 19:51:33 +02:00
}
if ( level > = 2 ) //wood & ore
{
2011-07-05 09:14:07 +03:00
FILL_FIELD ( woodOre , g - > second . resources [ Res : : WOOD ] + g - > second . resources [ Res : : ORE ] )
2010-02-01 19:51:33 +02:00
}
if ( level > = 3 ) //mercury, sulfur, crystal, gems
{
2011-07-05 09:14:07 +03:00
FILL_FIELD ( mercSulfCrystGems , g - > second . resources [ Res : : MERCURY ] + g - > second . resources [ Res : : SULFUR ] + g - > second . resources [ Res : : CRYSTAL ] + g - > second . resources [ Res : : GEMS ] )
2010-02-01 19:51:33 +02:00
}
if ( level > = 4 ) //obelisks found
{
//TODO
}
if ( level > = 5 ) //artifacts
{
2010-02-11 21:18:30 +02:00
FILL_FIELD ( artifacts , statsHLP : : getNumberOfArts ( & g - > second ) )
2010-02-01 19:51:33 +02:00
}
if ( level > = 6 ) //army strength
{
//TODO
}
if ( level > = 7 ) //income
{
//TODO
}
2010-02-06 15:49:14 +02:00
if ( level > = 8 ) //best hero's stats
{
2010-02-07 17:06:14 +02:00
//already set in lvl 1 handling
2010-02-06 15:49:14 +02:00
}
if ( level > = 9 ) //personality
{
for ( std : : map < ui8 , PlayerState > : : const_iterator g = players . begin ( ) ; g ! = players . end ( ) ; + + g )
{
if ( g - > second . color = = 255 ) //do nothing for neutral player
continue ;
if ( g - > second . human )
{
tgi . personality [ g - > second . color ] = - 1 ;
}
else //AI
{
2010-08-03 14:36:52 +03:00
tgi . personality [ g - > second . color ] = map - > players [ g - > second . color ] . AITactic ;
2010-02-06 15:49:14 +02:00
}
2012-02-16 20:10:58 +03:00
2010-02-06 15:49:14 +02:00
}
}
if ( level > = 10 ) //best creature
{
//best creatures belonging to player (highest AI value)
for ( std : : map < ui8 , PlayerState > : : const_iterator g = players . begin ( ) ; g ! = players . end ( ) ; + + g )
{
if ( g - > second . color = = 255 ) //do nothing for neutral player
continue ;
int bestCre = - 1 ; //best creature's ID
for ( int b = 0 ; b < g - > second . heroes . size ( ) ; + + b )
{
2010-05-02 21:20:26 +03:00
for ( TSlots : : const_iterator it = g - > second . heroes [ b ] - > Slots ( ) . begin ( ) ; it ! = g - > second . heroes [ b ] - > Slots ( ) . end ( ) ; + + it )
2010-02-06 15:49:14 +02:00
{
2010-11-22 02:34:46 +02:00
int toCmp = it - > second - > type - > idNumber ; //ID of creature we should compare with the best one
2010-05-02 21:20:26 +03:00
if ( bestCre = = - 1 | | VLC - > creh - > creatures [ bestCre ] - > AIValue < VLC - > creh - > creatures [ toCmp ] - > AIValue )
2010-02-06 15:49:14 +02:00
{
bestCre = toCmp ;
}
}
}
tgi . bestCreature [ g - > second . color ] = bestCre ;
}
}
2010-02-01 19:51:33 +02:00
# undef FILL_FIELD
}
2010-01-29 22:52:45 +02:00
int CGameState : : lossCheck ( ui8 player ) const
{
2011-05-10 01:20:47 +03:00
const PlayerState * p = CGameInfoCallback : : getPlayer ( player ) ;
2010-02-01 21:19:42 +02:00
//if(map->lossCondition.typeOfLossCon == lossStandard)
2010-01-29 22:52:45 +02:00
if ( checkForStandardLoss ( player ) )
return - 1 ;
2010-07-30 14:29:42 +03:00
if ( p - > enteredLosingCheatCode )
{
return 1 ;
}
2010-01-29 22:52:45 +02:00
if ( p - > human ) //special loss condition applies only to human player
{
switch ( map - > lossCondition . typeOfLossCon )
{
2011-12-14 00:23:17 +03:00
case ELossConditionType : : LOSSCASTLE :
2010-01-29 22:52:45 +02:00
{
const CGTownInstance * t = dynamic_cast < const CGTownInstance * > ( map - > lossCondition . obj ) ;
assert ( t ) ;
if ( t - > tempOwner ! = player )
return 1 ;
}
break ;
2011-12-14 00:23:17 +03:00
case ELossConditionType : : LOSSHERO :
2010-01-29 22:52:45 +02:00
{
const CGHeroInstance * h = dynamic_cast < const CGHeroInstance * > ( map - > lossCondition . obj ) ;
assert ( h ) ;
if ( h - > tempOwner ! = player )
return 1 ;
}
break ;
2011-12-14 00:23:17 +03:00
case ELossConditionType : : TIMEEXPIRES :
2010-01-29 22:52:45 +02:00
if ( map - > lossCondition . timeLimit < day )
return 1 ;
break ;
}
}
2010-02-02 01:30:03 +02:00
if ( ! p - > towns . size ( ) & & p - > daysWithoutCastle > = 7 )
return 2 ;
2010-01-29 22:52:45 +02:00
return false ;
}
2010-12-20 15:04:24 +02:00
bmap < ui32 , ConstTransitivePtr < CGHeroInstance > > CGameState : : unusedHeroesFromPool ( )
2010-07-08 08:52:11 +03:00
{
2010-12-20 15:04:24 +02:00
bmap < ui32 , ConstTransitivePtr < CGHeroInstance > > pool = hpool . heroesPool ;
2010-07-08 08:52:11 +03:00
for ( std : : map < ui8 , PlayerState > : : iterator i = players . begin ( ) ; i ! = players . end ( ) ; i + + )
2010-12-20 15:04:24 +02:00
for ( std : : vector < ConstTransitivePtr < CGHeroInstance > > : : iterator j = i - > second . availableHeroes . begin ( ) ; j ! = i - > second . availableHeroes . end ( ) ; j + + )
2010-07-08 08:52:11 +03:00
if ( * j )
pool . erase ( ( * * j ) . subID ) ;
return pool ;
}
2011-02-04 16:58:14 +02:00
void CGameState : : buildBonusSystemTree ( )
2011-02-22 11:47:25 +02:00
{
buildGlobalTeamPlayerTree ( ) ;
attachArmedObjects ( ) ;
BOOST_FOREACH ( CGTownInstance * t , map - > towns )
{
t - > deserializationFix ( ) ;
}
2012-02-16 20:10:58 +03:00
// CStackInstance <-> CCreature, CStackInstance <-> CArmedInstance, CArtifactInstance <-> CArtifact
2011-02-22 11:47:25 +02:00
// are provided on initializing / deserializing
}
void CGameState : : deserializationFix ( )
{
buildGlobalTeamPlayerTree ( ) ;
attachArmedObjects ( ) ;
}
void CGameState : : buildGlobalTeamPlayerTree ( )
2010-11-18 20:07:57 +02:00
{
2011-02-04 16:58:14 +02:00
for ( std : : map < ui8 , TeamState > : : iterator k = teams . begin ( ) ; k ! = teams . end ( ) ; + + k )
{
TeamState * t = & k - > second ;
t - > attachTo ( & globalEffects ) ;
BOOST_FOREACH ( ui8 teamMember , k - > second . players )
{
PlayerState * p = getPlayer ( teamMember ) ;
assert ( p ) ;
p - > attachTo ( t ) ;
}
}
2011-02-22 11:47:25 +02:00
}
2011-02-04 16:58:14 +02:00
2011-02-22 11:47:25 +02:00
void CGameState : : attachArmedObjects ( )
{
2011-02-04 16:58:14 +02:00
BOOST_FOREACH ( CGObjectInstance * obj , map - > objects )
{
if ( CArmedInstance * armed = dynamic_cast < CArmedInstance * > ( obj ) )
2011-02-22 11:47:25 +02:00
armed - > whatShouldBeAttached ( ) - > attachTo ( armed - > whereShouldBeAttached ( this ) ) ;
2011-02-04 16:58:14 +02:00
}
2010-11-18 20:07:57 +02:00
}
2012-02-17 22:30:40 +03:00
void CGameState : : giveHeroArtifact ( CGHeroInstance * h , int aid )
{
CArtifact * const artifact = VLC - > arth - > artifacts [ aid ] ; //pointer to constant object
CArtifactInstance * ai = CArtifactInstance : : createNewArtifactInstance ( artifact ) ;
map - > addNewArtifactInstance ( ai ) ;
2012-04-14 05:20:22 +03:00
ai - > putAt ( ArtifactLocation ( h , ai - > firstAvailableSlot ( h ) ) ) ;
2012-02-17 22:30:40 +03:00
}
2009-03-19 21:04:46 +02:00
int3 CPath : : startPos ( ) const
2009-03-19 16:17:19 +02:00
{
2009-03-19 21:04:46 +02:00
return nodes [ nodes . size ( ) - 1 ] . coord ;
2009-03-19 16:17:19 +02:00
}
void CPath : : convert ( ui8 mode ) //mode=0 -> from 'manifest' to 'object'
{
if ( mode = = 0 )
{
2011-12-14 00:23:17 +03:00
for ( ui32 i = 0 ; i < nodes . size ( ) ; i + + )
2009-03-19 16:17:19 +02:00
{
nodes [ i ] . coord = CGHeroInstance : : convertPosition ( nodes [ i ] . coord , true ) ;
}
}
}
2009-03-19 21:04:46 +02:00
int3 CPath : : endPos ( ) const
2009-03-19 16:17:19 +02:00
{
2009-03-19 21:04:46 +02:00
return nodes [ 0 ] . coord ;
2009-03-19 16:17:19 +02:00
}
2009-08-30 15:47:40 +03:00
CGPathNode : : CGPathNode ( )
: coord ( - 1 , - 1 , - 1 )
{
accessible = 0 ;
land = 0 ;
moveRemains = 0 ;
turns = 255 ;
theNodeBefore = NULL ;
}
2012-01-03 04:55:26 +03:00
bool CGPathNode : : reachable ( ) const
{
return turns < 255 ;
}
2009-08-30 15:47:40 +03:00
bool CPathsInfo : : getPath ( const int3 & dst , CGPath & out )
{
2011-09-03 05:54:33 +03:00
assert ( isValid ) ;
2009-08-30 15:47:40 +03:00
out . nodes . clear ( ) ;
const CGPathNode * curnode = & nodes [ dst . x ] [ dst . y ] [ dst . z ] ;
2011-09-19 23:50:25 +03:00
if ( ! curnode - > theNodeBefore )
2009-08-30 15:47:40 +03:00
return false ;
2010-05-15 18:00:19 +03:00
2009-09-07 05:29:44 +03:00
while ( curnode )
2009-08-30 15:47:40 +03:00
{
2010-05-15 18:00:19 +03:00
CGPathNode cpn = * curnode ;
2009-08-30 15:47:40 +03:00
curnode = curnode - > theNodeBefore ;
2010-05-15 18:00:19 +03:00
out . nodes . push_back ( cpn ) ;
2009-08-30 15:47:40 +03:00
}
return true ;
}
CPathsInfo : : CPathsInfo ( const int3 & Sizes )
: sizes ( Sizes )
{
2009-11-13 18:02:25 +02:00
hero = NULL ;
2009-08-30 15:47:40 +03:00
nodes = new CGPathNode * * [ sizes . x ] ;
for ( int i = 0 ; i < sizes . x ; i + + )
{
nodes [ i ] = new CGPathNode * [ sizes . y ] ;
for ( int j = 0 ; j < sizes . y ; j + + )
{
nodes [ i ] [ j ] = new CGPathNode [ sizes . z ] ;
}
}
}
CPathsInfo : : ~ CPathsInfo ( )
{
for ( int i = 0 ; i < sizes . x ; i + + )
{
for ( int j = 0 ; j < sizes . y ; j + + )
{
delete [ ] nodes [ i ] [ j ] ;
}
delete [ ] nodes [ i ] ;
}
delete [ ] nodes ;
2009-09-07 05:29:44 +03:00
}
int3 CGPath : : startPos ( ) const
{
return nodes [ nodes . size ( ) - 1 ] . coord ;
}
int3 CGPath : : endPos ( ) const
{
return nodes [ 0 ] . coord ;
}
void CGPath : : convert ( ui8 mode )
{
if ( mode = = 0 )
{
2011-12-14 00:23:17 +03:00
for ( ui32 i = 0 ; i < nodes . size ( ) ; i + + )
2009-09-07 05:29:44 +03:00
{
nodes [ i ] . coord = CGHeroInstance : : convertPosition ( nodes [ i ] . coord , true ) ;
}
}
}
2012-02-16 20:10:58 +03:00
PlayerState : : PlayerState ( )
: color ( - 1 ) , currentSelection ( 0xffffffff ) , enteredWinningCheatCode ( 0 ) ,
2010-10-31 00:53:41 +03:00
enteredLosingCheatCode ( 0 ) , status ( INGAME ) , daysWithoutCastle ( 0 )
2009-09-07 05:29:44 +03:00
{
2011-07-13 21:39:02 +03:00
setNodeType ( PLAYER ) ;
2009-10-04 05:02:45 +03:00
}
2010-02-07 17:06:14 +02:00
2010-12-12 01:11:26 +02:00
std : : string PlayerState : : nodeName ( ) const
{
return " Player " + ( color < VLC - > generaltexth - > capColors . size ( ) ? VLC - > generaltexth - > capColors [ color ] : boost : : lexical_cast < std : : string > ( color ) ) ;
}
2010-11-13 22:26:15 +02:00
// void PlayerState::getParents(TCNodes &out, const CBonusSystemNode *root /*= NULL*/) const
// {
// return; //no loops possible
// }
2012-02-16 20:10:58 +03:00
//
2010-11-13 22:26:15 +02:00
// void PlayerState::getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root /*= NULL*/) const
// {
// for (std::vector<CGHeroInstance *>::const_iterator it = heroes.begin(); it != heroes.end(); it++)
// {
// if (*it != root)
// (*it)->getBonuses(out, selector, this);
// }
// }
2010-05-14 05:18:37 +03:00
2012-06-13 16:04:06 +03:00
InfoAboutArmy : : InfoAboutArmy ( ) :
owner ( GameConstants : : NEUTRAL_PLAYER )
{ }
InfoAboutArmy : : InfoAboutArmy ( const CArmedInstance * Army , bool detailed )
{
initFromArmy ( Army , detailed ) ;
}
void InfoAboutArmy : : initFromArmy ( const CArmedInstance * Army , bool detailed )
2010-02-07 17:06:14 +02:00
{
2012-06-13 16:04:06 +03:00
army = ArmyDescriptor ( Army , detailed ) ;
owner = Army - > tempOwner ;
name = Army - > getHoverText ( ) ;
}
void InfoAboutHero : : assign ( const InfoAboutHero & iah )
{
InfoAboutArmy : : operator = ( iah ) ;
details = ( iah . details ? new Details ( * iah . details ) : NULL ) ;
hclass = iah . hclass ;
portrait = iah . portrait ;
2010-02-07 17:06:14 +02:00
}
2012-06-13 16:04:06 +03:00
InfoAboutHero : : InfoAboutHero ( ) :
details ( nullptr ) ,
hclass ( nullptr ) ,
portrait ( - 1 )
{ }
InfoAboutHero : : InfoAboutHero ( const InfoAboutHero & iah ) :
InfoAboutArmy ( )
2010-02-07 19:56:06 +02:00
{
assign ( iah ) ;
}
2012-06-13 16:04:06 +03:00
InfoAboutHero : : InfoAboutHero ( const CGHeroInstance * h , bool detailed )
{
initFromHero ( h , detailed ) ;
}
2010-02-07 17:06:14 +02:00
InfoAboutHero : : ~ InfoAboutHero ( )
{
delete details ;
}
2012-06-13 16:04:06 +03:00
InfoAboutHero & InfoAboutHero : : operator = ( const InfoAboutHero & iah )
2010-02-07 17:06:14 +02:00
{
2012-06-13 16:04:06 +03:00
assign ( iah ) ;
return * this ;
}
void InfoAboutHero : : initFromHero ( const CGHeroInstance * h , bool detailed )
{
if ( ! h )
return ;
initFromArmy ( h , detailed ) ;
2010-02-28 14:39:38 +02:00
2010-02-07 17:06:14 +02:00
hclass = h - > type - > heroClass ;
name = h - > name ;
portrait = h - > portrait ;
2012-02-16 20:10:58 +03:00
if ( detailed )
2010-02-07 17:06:14 +02:00
{
//include details about hero
details = new Details ;
2010-05-02 21:20:26 +03:00
details - > luck = h - > LuckVal ( ) ;
details - > morale = h - > MoraleVal ( ) ;
2010-02-07 17:06:14 +02:00
details - > mana = h - > mana ;
2011-12-14 00:23:17 +03:00
details - > primskills . resize ( GameConstants : : PRIMARY_SKILLS ) ;
2010-02-07 17:06:14 +02:00
2011-12-14 00:23:17 +03:00
for ( int i = 0 ; i < GameConstants : : PRIMARY_SKILLS ; i + + )
2010-02-07 17:06:14 +02:00
{
details - > primskills [ i ] = h - > getPrimSkillLevel ( i ) ;
}
}
}
2012-06-13 16:04:06 +03:00
InfoAboutTown : : InfoAboutTown ( ) :
details ( nullptr ) ,
tType ( nullptr ) ,
built ( 0 ) ,
fortLevel ( 0 )
2010-02-07 19:56:06 +02:00
{
2012-06-13 16:04:06 +03:00
2010-02-07 19:56:06 +02:00
}
2012-06-13 16:04:06 +03:00
InfoAboutTown : : InfoAboutTown ( const CGTownInstance * t , bool detailed )
2010-02-07 19:56:06 +02:00
{
2012-06-13 16:04:06 +03:00
initFromTown ( t , detailed ) ;
2010-02-13 17:56:34 +02:00
}
2010-05-08 21:56:38 +03:00
2012-06-13 16:04:06 +03:00
InfoAboutTown : : ~ InfoAboutTown ( )
{
delete details ;
}
void InfoAboutTown : : initFromTown ( const CGTownInstance * t , bool detailed )
{
initFromArmy ( t , detailed ) ;
army = ArmyDescriptor ( t - > getUpperArmy ( ) , detailed ) ;
built = t - > builded ;
fortLevel = t - > fortLevel ( ) ;
name = t - > name ;
tType = t - > town ;
2010-07-30 14:29:42 +03:00
2012-06-13 16:04:06 +03:00
if ( detailed )
{
//include details about hero
details = new Details ;
details - > goldIncome = t - > dailyIncome ( ) ;
details - > customRes = vstd : : contains ( t - > builtBuildings , 15 ) ;
details - > hallLevel = t - > hallLevel ( ) ;
details - > garrisonedHero = t - > garrisonHero ;
}
}
2010-12-06 01:10:02 +02:00
2012-06-13 16:04:06 +03:00
ArmyDescriptor : : ArmyDescriptor ( const CArmedInstance * army , bool detailed )
: isDetailed ( detailed )
2010-12-06 01:10:02 +02:00
{
for ( TSlots : : const_iterator i = army - > Slots ( ) . begin ( ) ; i ! = army - > Slots ( ) . end ( ) ; i + + )
{
if ( detailed )
( * this ) [ i - > first ] = * i - > second ;
else
( * this ) [ i - > first ] = CStackBasicDescriptor ( i - > second - > type , i - > second - > getQuantityID ( ) ) ;
}
}
2012-06-13 16:04:06 +03:00
ArmyDescriptor : : ArmyDescriptor ( )
: isDetailed ( false )
2010-12-06 01:10:02 +02:00
{
2011-01-21 04:36:30 +02:00
}
2011-08-25 18:24:37 +03:00
int ArmyDescriptor : : getStrength ( ) const
{
ui64 ret = 0 ;
if ( isDetailed )
{
for ( const_iterator i = begin ( ) ; i ! = end ( ) ; i + + )
ret + = i - > second . type - > AIValue * i - > second . count ;
}
else
{
for ( const_iterator i = begin ( ) ; i ! = end ( ) ; i + + )
ret + = i - > second . type - > AIValue * CCreature : : estimateCreatureCount ( i - > second . count ) ;
}
return ret ;
}
2011-01-21 04:36:30 +02:00
DuelParameters : : SideSettings : : StackSettings : : StackSettings ( )
: type ( - 1 ) , count ( 0 )
{
}
DuelParameters : : SideSettings : : StackSettings : : StackSettings ( si32 Type , si32 Count )
: type ( Type ) , count ( Count )
{
}
DuelParameters : : SideSettings : : SideSettings ( )
{
heroId = - 1 ;
}
DuelParameters : : DuelParameters ( )
{
terType = TerrainTile : : dirt ;
bfieldType = 15 ;
2011-02-06 19:26:27 +02:00
}
2011-02-21 06:13:00 +02:00
TeamState : : TeamState ( )
{
2011-07-13 21:39:02 +03:00
setNodeType ( TEAM ) ;
2011-05-30 22:20:14 +03:00
}
2011-09-19 23:50:25 +03:00
void CPathfinder : : initializeGraph ( )
{
CGPathNode * * * graph = out . nodes ;
for ( size_t i = 0 ; i < out . sizes . x ; + + i )
{
for ( size_t j = 0 ; j < out . sizes . y ; + + j )
{
for ( size_t k = 0 ; k < out . sizes . z ; + + k )
{
curPos = int3 ( i , j , k ) ;
const TerrainTile * tinfo = & gs - > map - > terrain [ i ] [ j ] [ k ] ;
CGPathNode & node = graph [ i ] [ j ] [ k ] ;
node . accessible = evaluateAccessibility ( tinfo ) ;
node . turns = 0xff ;
node . moveRemains = 0 ;
node . coord . x = i ;
node . coord . y = j ;
node . coord . z = k ;
node . land = tinfo - > tertype ! = TerrainTile : : water ;
node . theNodeBefore = NULL ;
}
}
}
}
void CPathfinder : : calculatePaths ( int3 src /*= int3(-1,-1,-1)*/ , int movement /*= -1*/ )
{
assert ( hero ) ;
assert ( hero = = getHero ( hero - > id ) ) ;
if ( src . x < 0 )
src = hero - > getPosition ( false ) ;
if ( movement < 0 )
movement = hero - > movement ;
out . hero = hero ;
out . hpos = src ;
if ( ! gs - > map - > isInTheMap ( src ) /* || !gs->map->isInTheMap(dest)*/ ) //check input
{
tlog1 < < " CGameState::calculatePaths: Hero outside the gs->map? How dare you... \n " ;
return ;
}
initializeGraph ( ) ;
//initial tile - set cost on 0 and add to the queue
CGPathNode & initialNode = * getNode ( src ) ;
initialNode . turns = 0 ;
initialNode . moveRemains = movement ;
mq . push_back ( & initialNode ) ;
std : : vector < int3 > neighbours ;
neighbours . reserve ( 16 ) ;
while ( ! mq . empty ( ) )
{
cp = mq . front ( ) ;
mq . pop_front ( ) ;
const int3 sourceGuardPosition = guardingCreaturePosition ( cp - > coord ) ;
bool guardedSource = ( sourceGuardPosition ! = int3 ( - 1 , - 1 , - 1 ) & & cp - > coord ! = src ) ;
ct = & gs - > map - > getTile ( cp - > coord ) ;
int movement = cp - > moveRemains , turn = cp - > turns ;
if ( ! movement )
{
movement = hero - > maxMovePoints ( cp - > land ) ;
turn + + ;
}
//add accessible neighbouring nodes to the queue
neighbours . clear ( ) ;
//handling subterranean gate => it's exit is the only neighbour
2011-12-14 00:23:17 +03:00
bool subterraneanEntry = ( ct - > topVisitableID ( ) = = GameConstants : : SUBTERRANEAN_GATE_TYPE & & useSubterraneanGates ) ;
2011-09-19 23:50:25 +03:00
if ( subterraneanEntry )
{
//try finding the exit gate
if ( const CGObjectInstance * outGate = getObj ( CGTeleport : : getMatchingGate ( ct - > visitableObjects . back ( ) - > id ) , false ) )
{
const int3 outPos = outGate - > visitablePos ( ) ;
//gs->getNeighbours(*getTile(outPos), outPos, neighbours, boost::logic::indeterminate, !cp->land);
neighbours . push_back ( outPos ) ;
}
else
{
//gate with no exit (blocked) -> do nothing with this node
continue ;
}
}
gs - > getNeighbours ( * ct , cp - > coord , neighbours , boost : : logic : : indeterminate , ! cp - > land ) ;
2011-12-14 00:23:17 +03:00
for ( ui32 i = 0 ; i < neighbours . size ( ) ; i + + )
2011-09-19 23:50:25 +03:00
{
const int3 & n = neighbours [ i ] ; //current neighbor
dp = getNode ( n ) ;
dt = & gs - > map - > getTile ( n ) ;
destTopVisObjID = dt - > topVisitableID ( ) ;
useEmbarkCost = 0 ; //0 - usual movement; 1 - embark; 2 - disembark
int turnAtNextTile = turn ;
const bool destIsGuardian = sourceGuardPosition = = n ;
if ( ! goodForLandSeaTransition ( ) )
continue ;
if ( ! canMoveBetween ( cp - > coord , dp - > coord ) | | dp - > accessible = = CGPathNode : : BLOCKED )
continue ;
//special case -> hero embarked a boat standing on a guarded tile -> we must allow to move away from that tile
2011-12-14 00:23:17 +03:00
if ( cp - > accessible = = CGPathNode : : VISITABLE & & guardedSource & & cp - > theNodeBefore - > land & & ct - > topVisitableID ( ) = = GameConstants : : BOATI_TYPE )
2011-09-19 23:50:25 +03:00
guardedSource = false ;
int cost = gs - > getMovementCost ( hero , cp - > coord , dp - > coord , movement ) ;
//special case -> moving from src Subterranean gate to dest gate -> it's free
2011-12-14 00:23:17 +03:00
if ( subterraneanEntry & & destTopVisObjID = = GameConstants : : SUBTERRANEAN_GATE_TYPE & & cp - > coord . z ! = dp - > coord . z )
2011-09-19 23:50:25 +03:00
cost = 0 ;
int remains = movement - cost ;
if ( useEmbarkCost )
{
remains = hero - > movementPointsAfterEmbark ( movement , cost , useEmbarkCost - 1 ) ;
cost = movement - remains ;
}
if ( remains < 0 )
{
//occurs rarely, when hero with low movepoints tries to leave the road
turnAtNextTile + + ;
2012-06-07 06:08:38 +03:00
int moveAtNextTile = hero - > maxMovePoints ( cp - > land ) ;
2011-09-19 23:50:25 +03:00
cost = gs - > getMovementCost ( hero , cp - > coord , dp - > coord , moveAtNextTile ) ; //cost must be updated, movement points changed :(
remains = moveAtNextTile - cost ;
}
if ( ( dp - > turns = = 0xff //we haven't been here before
| | dp - > turns > turnAtNextTile
| | ( dp - > turns > = turnAtNextTile & & dp - > moveRemains < remains ) ) //this route is faster
& & ( ! guardedSource | | destIsGuardian ) ) // Can step into tile of guard
{
assert ( dp ! = cp - > theNodeBefore ) ; //two tiles can't point to each other
dp - > moveRemains = remains ;
dp - > turns = turnAtNextTile ;
dp - > theNodeBefore = cp ;
2012-02-16 20:10:58 +03:00
const bool guardedDst = guardingCreaturePosition ( dp - > coord ) ! = int3 ( - 1 , - 1 , - 1 )
2011-09-19 23:50:25 +03:00
& & dp - > accessible = = CGPathNode : : BLOCKVIS ;
if ( dp - > accessible = = CGPathNode : : ACCESSIBLE
2011-10-08 19:58:25 +03:00
| | ( useEmbarkCost & & allowEmbarkAndDisembark )
2011-12-14 00:23:17 +03:00
| | destTopVisObjID = = GameConstants : : SUBTERRANEAN_GATE_TYPE
2011-09-19 23:50:25 +03:00
| | ( guardedDst & & ! guardedSource ) ) // Can step into a hostile tile once.
{
mq . push_back ( dp ) ;
}
}
} //neighbours loop
} //queue loop
out . isValid = true ;
}
CGPathNode * CPathfinder : : getNode ( const int3 & coord )
{
return & out . nodes [ coord . x ] [ coord . y ] [ coord . z ] ;
}
bool CPathfinder : : canMoveBetween ( const int3 & a , const int3 & b ) const
{
return gs - > checkForVisitableDir ( a , b ) & & gs - > checkForVisitableDir ( b , a ) ;
}
bool CPathfinder : : canStepOntoDst ( ) const
{
//TODO remove
assert ( 0 ) ;
return false ;
}
CGPathNode : : EAccessibility CPathfinder : : evaluateAccessibility ( const TerrainTile * tinfo ) const
{
CGPathNode : : EAccessibility ret = ( tinfo - > blocked ? CGPathNode : : BLOCKED : CGPathNode : : ACCESSIBLE ) ;
if ( tinfo - > tertype = = TerrainTile : : rock | | ! FoW [ curPos . x ] [ curPos . y ] [ curPos . z ] )
return CGPathNode : : BLOCKED ;
2012-02-16 20:10:58 +03:00
2011-09-19 23:50:25 +03:00
if ( tinfo - > visitable )
{
2011-12-14 00:23:17 +03:00
if ( tinfo - > visitableObjects . front ( ) - > ID = = 80 & & tinfo - > visitableObjects . back ( ) - > ID = = GameConstants : : HEROI_TYPE & & tinfo - > visitableObjects . back ( ) - > tempOwner ! = hero - > tempOwner ) //non-owned hero stands on Sanctuary
2011-09-19 23:50:25 +03:00
{
return CGPathNode : : BLOCKED ;
}
else
{
BOOST_FOREACH ( const CGObjectInstance * obj , tinfo - > visitableObjects )
{
if ( obj - > getPassableness ( ) & 1 < < hero - > tempOwner ) //special object instance specific passableness flag - overwrites other accessibility flags
{
ret = CGPathNode : : ACCESSIBLE ;
}
else if ( obj - > blockVisit )
{
return CGPathNode : : BLOCKVIS ;
}
2011-12-14 00:23:17 +03:00
else if ( obj - > ID ! = GameConstants : : EVENTI_TYPE ) //pathfinder should ignore placed events
2011-09-19 23:50:25 +03:00
{
ret = CGPathNode : : VISITABLE ;
}
}
}
}
else if ( gs - > map - > isInTheMap ( guardingCreaturePosition ( curPos ) )
& & ! tinfo - > blocked )
{
// Monster close by; blocked visit for battle.
return CGPathNode : : BLOCKVIS ;
}
return ret ;
}
bool CPathfinder : : goodForLandSeaTransition ( )
{
if ( cp - > land ! = dp - > land ) //hero can traverse land<->sea only in special circumstances
{
if ( cp - > land ) //from land to sea -> embark or assault hero on boat
{
if ( dp - > accessible = = CGPathNode : : ACCESSIBLE | | destTopVisObjID < 0 ) //cannot enter empty water tile from land -> it has to be visitable
2012-02-16 20:10:58 +03:00
return false ;
2011-12-14 00:23:17 +03:00
if ( destTopVisObjID ! = GameConstants : : HEROI_TYPE & & destTopVisObjID ! = GameConstants : : BOATI_TYPE ) //only boat or hero can be accessed from land
2011-09-19 23:50:25 +03:00
return false ;
2011-12-14 00:23:17 +03:00
if ( destTopVisObjID = = GameConstants : : BOATI_TYPE )
2012-02-16 20:10:58 +03:00
useEmbarkCost = 1 ;
2011-09-19 23:50:25 +03:00
}
else //disembark
{
//can disembark only on coastal tiles
2012-02-16 20:10:58 +03:00
if ( ! dt - > isCoastal ( ) )
2011-09-19 23:50:25 +03:00
return false ;
//tile must be accessible -> exception: unblocked blockvis tiles -> clear but guarded by nearby monster coast
2012-02-16 20:10:58 +03:00
if ( ( dp - > accessible ! = CGPathNode : : ACCESSIBLE & & ( dp - > accessible ! = CGPathNode : : BLOCKVIS | | dt - > blocked ) )
2012-01-03 04:55:26 +03:00
| | dt - > visitable ) //TODO: passableness problem -> town says it's passable (thus accessible) but we obviously can't disembark onto town gate
2011-09-19 23:50:25 +03:00
return false ; ;
useEmbarkCost = 2 ;
}
}
2012-02-16 20:10:58 +03:00
return true ;
2011-09-19 23:50:25 +03:00
}
2011-10-08 19:58:25 +03:00
CPathfinder : : CPathfinder ( CPathsInfo & _out , CGameState * _gs , const CGHeroInstance * _hero ) : CGameInfoCallback ( _gs , - 1 ) , out ( _out ) , hero ( _hero ) , FoW ( getPlayerTeam ( hero - > tempOwner ) - > fogOfWarMap )
2011-09-19 23:50:25 +03:00
{
useSubterraneanGates = true ;
allowEmbarkAndDisembark = true ;
2011-09-24 04:15:36 +03:00
}