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>
2013-01-03 15:19:20 +03:00
# include "Mapping/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"
2012-08-10 16:07:53 +03:00
# include "CModHandler.h"
2009-05-20 13:08:56 +03:00
# include "VCMI_Lib.h"
# include "Connection.h"
2013-01-03 15:19:20 +03:00
# include "Mapping/CMap.h"
# include "Mapping/CMapService.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"
2013-01-03 15:19:20 +03:00
# include "Mapping/CMapInfo.h"
2010-12-25 21:23:30 +02:00
# include "BattleState.h"
2012-08-01 15:02:54 +03:00
# include "JsonNode.h"
# include "Filesystem/CResourceLoader.h"
2011-12-14 00:23:17 +03:00
# include "GameConstants.h"
2012-11-20 20:53:45 +03:00
# include "RMG/CMapGenOptions.h"
2013-01-06 22:30:12 +03:00
# include "RMG/CMapGenerator.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
2012-11-11 00:56:19 +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
}
2012-12-06 22:03:47 +03:00
else if ( type = = ART_EVNTS )
{
2013-01-15 17:20:48 +03:00
dst = VLC - > arth - > artifacts [ ser ] - > EventText ( ) ;
2012-12-06 22:03:47 +03: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 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 :
2012-06-16 20:12:58 +03:00
boost : : replace_first ( dst , " %s " , 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 ) ;
2012-06-16 20:12:58 +03:00
boost : : replace_first ( dst , " %s " , hlp ) ;
2008-12-27 03:01:59 +02:00
}
2009-07-09 22:15:22 +03:00
break ;
case TREPLACE_NUMBER :
2012-06-16 20:12:58 +03:00
boost : : replace_first ( dst , " %d " , 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 :
2012-06-16 20:12:58 +03:00
boost : : replace_first ( dst , " %+d " , ' + ' + boost : : lexical_cast < std : : string > ( numbers [ nums + + ] ) ) ;
2010-08-26 10:23:08 +03:00
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;
{
2012-07-30 12:27:19 +03:00
if ( ! count )
addReplacement ( CRE_PL_NAMES , id ) ; //no creatures - just empty name (eg. defeat Angels)
else if ( count = = 1 )
2010-11-22 02:34:46 +02:00
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 . 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 )
{
2012-09-23 21:01:04 +03:00
case Obj : : 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 ;
}
2012-09-23 21:01:04 +03:00
case Obj : : 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
2012-09-23 21:01:04 +03:00
if ( nobj - > ID = = Obj : : HERO | | nobj - > ID = = Obj : : TOWN )
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
2012-09-24 19:14:53 +03:00
CGHeroInstance * CGameState : : HeroesPool : : pickHeroFor ( bool native , TPlayerColor 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 ;
2012-09-26 16:13:39 +03:00
if ( player > = GameConstants : : PLAYER_LIMIT )
2008-11-01 00:41:22 +02:00
{
2012-10-05 16:11:26 +03:00
tlog1 < < " Cannot pick hero for " < < town - > typeID < < " . 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 )
{
2012-09-24 19:14:53 +03:00
for ( auto 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
2012-12-14 18:32:53 +03:00
& & i - > second - > type - > heroClass - > faction = = 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
{
2012-10-06 11:47:13 +03:00
tlog1 < < " Cannot pick native hero for " < < int ( player ) < < " . Picking any... \n " ;
2009-08-05 03:05:37 +03:00
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 ;
2012-09-24 19:14:53 +03:00
for ( auto 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
}
}
2012-10-06 11:47:13 +03:00
if ( ! pool . size ( ) | | sum = = 0 )
2008-11-01 00:41:22 +02:00
{
tlog1 < < " There are no heroes available for player " < < player < < " ! \n " ;
2012-10-06 11:47:13 +03:00
return nullptr ;
2008-11-01 00:41:22 +02:00
}
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 ) ;
2012-10-26 20:51:05 +03:00
if ( ! map - > getHero ( h = ps . hero ) & & h > = 0 ) //we haven't used selected hero
2008-06-30 03:06:41 +03:00
return h ;
2012-09-22 20:23:28 +03:00
if ( scenarioOps - > mode = = StartInfo : : CAMPAIGN )
{
auto bonus = scenarioOps - > campState - > getBonusForCurrentMap ( ) ;
2012-09-24 22:23:11 +03:00
if ( bonus . is_initialized ( ) & & bonus - > type = = CScenarioTravel : : STravelBonus : : HERO & & owner = = bonus - > info1 )
2012-09-22 20:23:28 +03:00
{
2012-09-24 22:23:11 +03:00
if ( bonus - > info2 ! = 0xffff & & ! map - > getHero ( bonus - > info2 ) ) //not random and not taken
2012-09-22 20:23:28 +03:00
{
2012-09-24 22:23:11 +03:00
return bonus - > info2 ;
2012-09-22 20:23:28 +03:00
}
}
}
2012-10-06 11:47:13 +03:00
//list of heroes for this faction
std : : vector < si32 > factionHeroes ;
factionHeroes . reserve ( GameConstants : : HEROES_PER_TYPE * 2 ) ;
2010-10-31 00:53:41 +03:00
2012-10-06 11:47:13 +03:00
size_t firstHero = ps . castle * GameConstants : : HEROES_PER_TYPE * 2 ;
size_t lastHero = std : : min ( firstHero + GameConstants : : HEROES_PER_TYPE * 2 , VLC - > heroh - > heroes . size ( ) ) ;
//generate list of heroes
for ( si32 i = firstHero ; i < lastHero ; i + + )
factionHeroes . push_back ( i ) ;
// we need random order to select hero
2012-12-12 17:52:42 +03:00
std : : random_shuffle ( factionHeroes . begin ( ) , factionHeroes . end ( ) , [ ] ( size_t range )
{
return ran ( ) % range ;
} ) ;
2012-10-06 11:47:13 +03:00
for ( size_t i = 0 ; i < factionHeroes . size ( ) ; i + + )
2008-06-30 03:06:41 +03:00
{
2012-10-06 11:47:13 +03:00
if ( ! map - > getHero ( factionHeroes [ i ] ) )
return factionHeroes [ i ] ;
2008-06-30 03:06:41 +03:00
}
2012-10-06 11:47:13 +03:00
tlog3 < < " Warning: cannot find free hero - trying to get first available... " < < std : : endl ;
for ( int j = 0 ; j < VLC - > heroh - > heroes . size ( ) ; j + + )
if ( ! map - > getHero ( j ) )
return j ;
assert ( 0 ) ; //currrent code can't handle this situation
return - 1 ; // no available heroes at all
2008-06-30 03:06:41 +03:00
}
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 )
{
2012-12-24 13:18:30 +03:00
case Obj : : RANDOM_ART :
return std : : pair < int , int > ( Obj : : ARTIFACT , VLC - > arth - > getRandomArt ( CArtifact : : ART_TREASURE | CArtifact : : ART_MINOR | CArtifact : : ART_MAJOR | CArtifact : : ART_RELIC ) ) ;
2013-01-15 17:20:48 +03:00
case Obj : : RANDOM_TREASURE_ART :
2012-12-24 13:18:30 +03:00
return std : : pair < int , int > ( Obj : : ARTIFACT , VLC - > arth - > getRandomArt ( CArtifact : : ART_TREASURE ) ) ;
case Obj : : RANDOM_MINOR_ART :
return std : : pair < int , int > ( Obj : : ARTIFACT , VLC - > arth - > getRandomArt ( CArtifact : : ART_MINOR ) ) ;
case Obj : : RANDOM_MAJOR_ART :
return std : : pair < int , int > ( Obj : : ARTIFACT , VLC - > arth - > getRandomArt ( CArtifact : : ART_MAJOR ) ) ;
case Obj : : RANDOM_RELIC_ART :
return std : : pair < int , int > ( Obj : : ARTIFACT , VLC - > arth - > getRandomArt ( CArtifact : : ART_RELIC ) ) ;
case Obj : : RANDOM_HERO :
return std : : pair < int , int > ( Obj : : HERO , pickHero ( obj - > tempOwner ) ) ;
case Obj : : RANDOM_MONSTER :
return std : : pair < int , int > ( Obj : : MONSTER , VLC - > creh - > pickRandomMonster ( boost : : ref ( ran ) ) ) ;
case Obj : : RANDOM_MONSTER_L1 :
return std : : pair < int , int > ( Obj : : MONSTER , VLC - > creh - > pickRandomMonster ( boost : : ref ( ran ) , 1 ) ) ;
case Obj : : RANDOM_MONSTER_L2 :
return std : : pair < int , int > ( Obj : : MONSTER , VLC - > creh - > pickRandomMonster ( boost : : ref ( ran ) , 2 ) ) ;
case Obj : : RANDOM_MONSTER_L3 :
return std : : pair < int , int > ( Obj : : MONSTER , VLC - > creh - > pickRandomMonster ( boost : : ref ( ran ) , 3 ) ) ;
case Obj : : RANDOM_MONSTER_L4 :
return std : : pair < int , int > ( Obj : : MONSTER , VLC - > creh - > pickRandomMonster ( boost : : ref ( ran ) , 4 ) ) ;
case Obj : : RANDOM_RESOURCE :
return std : : pair < int , int > ( Obj : : RESOURCE , ran ( ) % 7 ) ; //now it's OH3 style, use %8 for mithril
case Obj : : RANDOM_TOWN :
2008-06-30 03:06:41 +03:00
{
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 ;
}
2012-09-05 15:49:23 +03:00
if ( f < 0 )
{
auto iter = VLC - > townh - > towns . begin ( ) ;
std : : advance ( iter , ran ( ) % VLC - > townh - > towns . size ( ) ) ;
f = iter - > first ;
}
2012-09-23 21:01:04 +03:00
return std : : pair < int , int > ( Obj : : TOWN , f ) ;
2008-06-30 03:06:41 +03:00
}
2012-12-24 13:18:30 +03:00
case Obj : : RANDOM_MONSTER_L5 :
return std : : pair < int , int > ( Obj : : MONSTER , VLC - > creh - > pickRandomMonster ( boost : : ref ( ran ) , 5 ) ) ;
case Obj : : RANDOM_MONSTER_L6 :
return std : : pair < int , int > ( Obj : : MONSTER , VLC - > creh - > pickRandomMonster ( boost : : ref ( ran ) , 6 ) ) ;
case Obj : : RANDOM_MONSTER_L7 :
return std : : pair < int , int > ( Obj : : MONSTER , VLC - > creh - > pickRandomMonster ( boost : : ref ( ran ) , 7 ) ) ;
2013-01-15 17:20:48 +03:00
case Obj : : RANDOM_DWELLING :
2012-12-24 13:18:30 +03:00
case Obj : : RANDOM_DWELLING_LVL :
case Obj : : RANDOM_DWELLING_FACTION :
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-12-19 19:35:58 +03:00
faction = ran ( ) % VLC - > townh - > factions . size ( ) ;
2012-05-11 22:03:40 +03:00
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-09-23 21:01:04 +03:00
if ( map - > objects [ i ] - > ID = = Obj : : RANDOM_TOWN
& & dynamic_cast < CGTownInstance * > ( map - > objects [ i ] . get ( ) ) - > identifier = = info - > identifier )
2012-05-11 22:03:40 +03:00
{
randomizeObject ( map - > objects [ i ] ) ; //we have to randomize the castle first
faction = map - > objects [ i ] - > subID ;
break ;
}
2012-09-23 21:01:04 +03:00
else if ( map - > objects [ i ] - > ID = = Obj : : TOWN
& & dynamic_cast < CGTownInstance * > ( map - > objects [ i ] . get ( ) ) - > identifier = = info - > identifier )
2012-05-11 22:03:40 +03:00
{
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 ) ;
2012-08-08 00:46:24 +03:00
int cid = VLC - > townh - > towns [ faction ] . creatures [ level ] [ 0 ] ;
2012-05-11 22:03:40 +03:00
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 } ;
2012-06-23 20:19:50 +03:00
std : : vector < int > factory ( factoryCreatures , factoryCreatures + ARRAY_COUNT ( factoryCreatures ) ) ;
2012-06-01 14:35:31 +03:00
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 )
2012-10-07 17:58:48 +03:00
{
2012-06-01 14:35:31 +03:00
tlog0 < < " Error: failed to find creature for dwelling of " < < int ( faction ) < < " of level " < < int ( level ) < < " \n " ;
2012-10-07 17:58:48 +03:00
auto iter = VLC - > objh - > cregens . begin ( ) ;
std : : advance ( iter , ran ( ) % VLC - > objh - > cregens . size ( ) ) ;
result = std : : pair < int , int > ( 17 , iter - > first ) ;
}
2012-06-01 14:35:31 +03:00
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
{
2012-09-23 21:01:04 +03:00
if ( cur - > ID = = Obj : : TOWN ) //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 ( ) )
2012-11-13 14:52:23 +03:00
t - > defInfo = VLC - > dobjinfo - > capitols [ t - > subID ] ;
2008-06-30 03:06:41 +03:00
else if ( t - > hasFort ( ) )
2012-11-13 14:52:23 +03:00
t - > defInfo = VLC - > dobjinfo - > gobjs [ Obj : : TOWN ] [ t - > subID ] ;
2008-06-30 03:06:41 +03:00
else
2012-11-13 14:52:23 +03:00
t - > defInfo = VLC - > dobjinfo - > villages [ t - > subID ] ;
2008-06-30 03:06:41 +03:00
}
return ;
}
2012-09-23 21:01:04 +03:00
else if ( ran . first = = Obj : : HERO ) //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 ] ;
2012-12-14 18:32:53 +03:00
h - > randomizeArmy ( h - > type - > heroClass - > faction ) ;
2008-06-30 03:06:41 +03:00
map - > heroes . push_back ( h ) ;
return ; //TODO: maybe we should do something with definfo?
}
2012-09-23 21:01:04 +03:00
else if ( ran . first = = Obj : : TOWN ) //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 ;
2012-11-13 14:52:23 +03:00
//FIXME: copy-pasted from above
t - > town = & VLC - > townh - > towns [ t - > subID ] ;
2008-06-30 03:06:41 +03:00
if ( t - > hasCapitol ( ) )
2012-11-13 14:52:23 +03:00
t - > defInfo = VLC - > dobjinfo - > capitols [ t - > subID ] ;
2008-06-30 03:06:41 +03:00
else if ( t - > hasFort ( ) )
2012-11-13 14:52:23 +03:00
t - > defInfo = VLC - > dobjinfo - > gobjs [ Obj : : TOWN ] [ t - > subID ] ;
2008-06-30 03:06:41 +03:00
else
2012-11-13 14:52:23 +03:00
t - > defInfo = VLC - > dobjinfo - > 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
2012-11-13 14:52:23 +03:00
map - > customDefs . 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
2013-02-02 11:29:57 +03:00
int CGameState : : getDate ( Date : : EDateType mode ) const
2008-07-25 20:28:28 +03:00
{
int temp ;
switch ( mode )
{
2013-02-02 11:29:57 +03:00
case Date : : DAY :
2008-07-25 20:28:28 +03:00
return day ;
break ;
2013-02-02 11:29:57 +03:00
case Date : : DAY_OF_WEEK : //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 ;
2013-02-02 11:29:57 +03:00
case Date : : WEEK : //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 ;
2013-02-02 11:29:57 +03:00
case Date : : MONTH : //current month
2012-02-16 20:10:58 +03:00
return ( ( day - 1 ) / 28 ) + 1 ;
2008-07-25 20:28:28 +03:00
break ;
2013-02-02 11:29:57 +03:00
case Date : : DAY_OF_MONTH : //day of month
2010-08-22 10:11:46 +03:00
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 ;
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 ) ;
2012-11-06 19:39:29 +03:00
int terrain = t . terType ;
2012-11-11 00:56:19 +03:00
if ( t . isCoastal ( ) & & ! t . isWater ( ) )
2012-10-26 20:51:05 +03:00
terrain = ETerrainType : : SAND ;
2012-04-08 05:29:11 +03:00
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
{
2012-09-22 18:16:45 +03:00
auto giveCampaignBonusToHero = [ & ] ( CGHeroInstance * hero )
2010-07-31 16:55:05 +03:00
{
2012-09-24 22:23:11 +03:00
const boost : : optional < CScenarioTravel : : STravelBonus > & curBonus = scenarioOps - > campState - > getBonusForCurrentMap ( ) ;
if ( ! curBonus )
return ;
if ( curBonus - > isBonusForHero ( ) )
2010-07-31 16:55:05 +03:00
{
2012-09-22 18:16:45 +03:00
//apply bonus
2012-09-24 22:23:11 +03:00
switch ( curBonus - > type )
2010-07-31 16:55:05 +03:00
{
2012-09-22 18:16:45 +03:00
case CScenarioTravel : : STravelBonus : : SPELL :
2012-09-24 22:23:11 +03:00
hero - > spells . insert ( curBonus - > info2 ) ;
2012-09-22 18:16:45 +03:00
break ;
case CScenarioTravel : : STravelBonus : : MONSTER :
2010-07-31 16:55:05 +03:00
{
2012-09-22 18:16:45 +03:00
for ( int i = 0 ; i < GameConstants : : ARMY_SIZE ; i + + )
2010-08-01 17:40:34 +03:00
{
2012-09-22 18:16:45 +03:00
if ( hero - > slotEmpty ( i ) )
2010-08-01 17:40:34 +03:00
{
2012-09-24 22:23:11 +03:00
hero - > addToSlot ( i , curBonus - > info2 , curBonus - > info3 ) ;
2012-09-22 18:16:45 +03:00
break ;
2010-08-01 17:40:34 +03:00
}
}
2012-09-22 18:16:45 +03:00
}
break ;
case CScenarioTravel : : STravelBonus : : ARTIFACT :
2012-09-24 22:23:11 +03:00
gs - > giveHeroArtifact ( hero , curBonus - > info2 ) ;
2012-09-22 18:16:45 +03:00
break ;
case CScenarioTravel : : STravelBonus : : SPELL_SCROLL :
{
2012-09-24 22:23:11 +03:00
CArtifactInstance * scroll = CArtifactInstance : : createScroll ( VLC - > spellh - > spells [ curBonus - > info2 ] ) ;
2012-09-22 18:16:45 +03:00
scroll - > putAt ( ArtifactLocation ( hero , scroll - > firstAvailableSlot ( hero ) ) ) ;
}
break ;
case CScenarioTravel : : STravelBonus : : PRIMARY_SKILL :
{
2012-09-24 22:23:11 +03:00
const ui8 * ptr = reinterpret_cast < const ui8 * > ( & curBonus - > info2 ) ;
2012-09-22 18:16:45 +03:00
for ( int g = 0 ; g < GameConstants : : PRIMARY_SKILLS ; + + g )
2010-07-31 16:55:05 +03:00
{
2012-09-22 18:16:45 +03:00
int val = ptr [ g ] ;
if ( val = = 0 )
2010-07-31 16:55:05 +03:00
{
2012-09-22 18:16:45 +03:00
continue ;
2010-07-31 16:55:05 +03:00
}
2012-09-22 18:16:45 +03:00
Bonus * bb = new Bonus ( Bonus : : PERMANENT , Bonus : : PRIMARY_SKILL , Bonus : : CAMPAIGN_BONUS , val , scenarioOps - > campState - > currentMap , g ) ;
hero - > addNewBonus ( bb ) ;
2010-07-31 16:55:05 +03:00
}
}
2012-09-22 18:16:45 +03:00
break ;
case CScenarioTravel : : STravelBonus : : SECONDARY_SKILL :
2012-09-24 22:23:11 +03:00
hero - > setSecSkillLevel ( static_cast < CGHeroInstance : : SecondarySkill > ( curBonus - > info2 ) , curBonus - > info3 , true ) ;
2012-09-22 18:16:45 +03:00
break ;
2010-07-31 16:55:05 +03:00
}
}
2012-09-22 18:16:45 +03:00
} ;
2010-07-31 16:55:05 +03:00
2012-09-22 18:16:45 +03:00
auto getHumanPlayerInfo = [ & ] ( ) - > std : : vector < const PlayerSettings * >
{
std : : vector < const PlayerSettings * > ret ;
2012-11-11 00:56:19 +03:00
for ( auto it = scenarioOps - > playerInfos . cbegin ( ) ;
2012-09-22 18:16:45 +03:00
it ! = scenarioOps - > playerInfos . cend ( ) ; + + it )
2010-07-31 16:55:05 +03:00
{
2012-12-02 15:21:44 +03:00
if ( it - > second . playerID ! = PlayerSettings : : PLAYER_AI )
2012-09-22 18:16:45 +03:00
ret . push_back ( & it - > second ) ;
2010-07-31 16:55:05 +03:00
}
2012-09-22 18:16:45 +03:00
return ret ;
} ;
2010-08-30 17:52:18 +03:00
2012-09-22 18:16:45 +03:00
auto replaceHero = [ & ] ( int objId , CGHeroInstance * ghi )
{
ghi - > id = objId ;
gs - > map - > objects [ objId ] = ghi ;
gs - > map - > heroes . push_back ( ghi ) ;
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 :
2012-11-20 20:53:45 +03:00
{
if ( scenarioOps - > createRandomMap )
{
tlog0 < < " Create random map. " < < std : : endl ;
2013-01-06 22:30:12 +03:00
// Create player settings for RMG
std : : map < TPlayerColor , CMapGenerator : : CPlayerSettings > players ;
BOOST_FOREACH ( auto pInfo , scenarioOps - > playerInfos )
{
const PlayerSettings & startSettings = pInfo . second ;
CMapGenerator : : CPlayerSettings player ;
player . setColor ( startSettings . color ) ;
player . setStartingTown ( startSettings . castle ) ;
if ( startSettings . playerID > 0 )
{
player . setPlayerType ( CMapGenerator : : CPlayerSettings : : HUMAN ) ;
}
else if ( startSettings . compOnly )
{
player . setPlayerType ( CMapGenerator : : CPlayerSettings : : COMP_ONLY ) ;
}
players [ player . getColor ( ) ] = player ;
}
// Gen map
CMapGenerator mapGen ( * scenarioOps - > mapGenOptions , players , scenarioOps - > seedToBeUsed ) ;
map = mapGen . generate ( ) . release ( ) ;
// Update starting options
2013-01-20 17:43:58 +03:00
for ( int i = 0 ; i < map - > players . size ( ) ; + + i )
2013-01-06 22:30:12 +03:00
{
2013-01-20 17:43:58 +03:00
const PlayerInfo & pInfo = map - > players [ i ] ;
if ( pInfo . canComputerPlay | | pInfo . canHumanPlay )
2013-01-06 22:30:12 +03:00
{
2013-01-20 17:43:58 +03:00
PlayerSettings & pSettings = scenarioOps - > playerInfos [ i ] ;
pSettings . compOnly = ! pInfo . canHumanPlay ;
pSettings . team = pInfo . team ;
pSettings . castle = pInfo . defaultCastle ( ) ;
if ( pSettings . playerID = = PlayerSettings : : PLAYER_AI & & pSettings . name . empty ( ) )
{
pSettings . name = VLC - > generaltexth - > allTexts [ 468 ] ;
}
pSettings . color = i ;
2013-01-06 22:30:12 +03:00
}
else
{
2013-01-20 17:43:58 +03:00
scenarioOps - > playerInfos . erase ( i ) ;
2013-01-06 22:30:12 +03:00
}
}
2013-01-20 17:43:58 +03:00
2012-11-20 20:53:45 +03:00
}
else
{
tlog0 < < " Open map file: " < < scenarioOps - > mapname < < std : : endl ;
map = CMapService : : loadMap ( scenarioOps - > mapname ) . release ( ) ;
}
}
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
{
2012-11-13 14:52:23 +03:00
tlog0 < < " Open campaign map file: " < < scenarioOps - > campState - > currentMap < < std : : endl ;
2012-09-21 20:59:54 +03:00
auto campaign = scenarioOps - > campState ;
assert ( vstd : : contains ( campaign - > camp - > mapPieces , scenarioOps - > campState - > currentMap ) ) ;
2010-08-18 12:50:25 +03:00
2012-11-13 14:52:23 +03:00
std : : string & mapContent = campaign - > camp - > mapPieces [ scenarioOps - > campState - > currentMap ] ;
auto buffer = reinterpret_cast < const ui8 * > ( mapContent . data ( ) ) ;
map = CMapService : : loadMap ( buffer , mapContent . size ( ) ) . release ( ) ;
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 :
2012-07-26 03:48:44 +03:00
initDuel ( ) ;
return ;
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 ;
//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 ;
2010-02-10 04:56:00 +02:00
2012-09-22 18:16:45 +03:00
tlog4 < < " Initialization: " ;
tlog4 < < " \t Picking grail position " ;
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
2012-11-13 14:52:23 +03:00
for ( int i = 0 ; i < map - > width ; i + + )
{
for ( int j = 0 ; j < map - > height ; j + + )
{
2012-11-20 20:53:45 +03:00
for ( int k = 0 ; k < ( map - > twoLevel ? 2 : 1 ) ; k + + )
2012-11-13 14:52:23 +03:00
{
const TerrainTile & t = map - > terrain [ i ] [ j ] [ k ] ;
if ( ! t . blocked
2012-02-16 20:10:58 +03:00
& & ! t . visitable
2012-11-06 19:39:29 +03:00
& & t . terType ! = ETerrainType : : WATER
& & t . terType ! = ETerrainType : : ROCK
2010-02-10 04:56:00 +02:00
& & 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 )
2012-09-23 21:01:04 +03:00
if ( map - > objects [ no ] - > ID = = Obj : : HOLE )
2010-02-10 04:56:00 +02:00
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 " ;
2012-11-13 14:52:23 +03:00
}
2010-02-10 04:56:00 +02:00
2008-06-30 03:06:41 +03:00
//picking random factions for players
2012-09-22 18:16:45 +03:00
tlog4 < < " \t Picking random factions for players " ;
2012-09-24 19:14:53 +03:00
for ( auto 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
{
2012-09-23 17:32:49 +03:00
int randomID = ran ( ) % map - > players [ it - > first ] . allowedFactions . size ( ) ;
auto iter = map - > players [ it - > first ] . allowedFactions . begin ( ) ;
std : : advance ( iter , randomID ) ;
it - > second . castle = * iter ;
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
2012-09-22 18:16:45 +03:00
tlog4 < < " \t 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
2012-09-23 21:01:04 +03:00
if ( obj - > ID = = Obj : : FAVORABLE_WINDS )
2010-07-09 07:29:11 +03:00
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 ) )
2012-10-26 20:51:05 +03:00
map - > getTile ( pos ) . extTileFlags | = 128 ;
2010-07-09 07:29:11 +03:00
}
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-09-22 18:16:45 +03:00
tlog4 < < " \t Creating player entries in gs " ;
2012-09-24 19:14:53 +03:00
for ( auto 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
{
2012-09-24 19:14:53 +03:00
std : : pair < TPlayerColor , PlayerState > ins ( it - > first , PlayerState ( ) ) ;
2010-08-02 17:29:30 +03:00
ins . second . color = ins . first ;
2012-12-02 15:21:44 +03:00
ins . second . human = it - > second . playerID ;
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****************************************/
2012-09-22 18:16:45 +03:00
tlog4 < < " \t Giving starting hero " ;
2008-07-27 20:07:37 +03:00
{
2012-09-25 17:40:39 +03:00
bool campaignGiveHero = false ;
2012-09-25 11:07:32 +03:00
if ( scenarioOps - > campState )
2008-07-27 20:07:37 +03:00
{
2012-09-25 11:07:32 +03:00
auto bonus = scenarioOps - > campState - > getBonusForCurrentMap ( ) ;
if ( bonus . is_initialized ( ) )
2012-09-24 22:23:11 +03:00
{
2012-09-25 17:40:39 +03:00
campaignGiveHero = scenarioOps - > mode = = StartInfo : : CAMPAIGN & &
bonus . get ( ) . type = = CScenarioTravel : : STravelBonus : : HERO ;
}
}
for ( auto it = scenarioOps - > playerInfos . begin ( ) ; it ! = scenarioOps - > playerInfos . end ( ) ; + + it )
{
const PlayerInfo & p = map - > players [ it - > first ] ;
2012-12-02 15:21:44 +03:00
bool generateHero = ( p . generateHeroAtMainTown | |
( it - > second . playerID ! = PlayerSettings : : PLAYER_AI & & campaignGiveHero ) ) & & p . hasMainTown ;
2012-09-25 17:40:39 +03:00
if ( generateHero & & vstd : : contains ( scenarioOps - > playerInfos , it - > first ) )
{
int3 hpos = p . posOfMainTown ;
hpos . x + = 1 ;
int h = pickHero ( it - > first ) ;
if ( it - > second . hero = = - 1 )
it - > second . hero = h ;
CGHeroInstance * nnn = static_cast < CGHeroInstance * > ( createObject ( Obj : : HERO , h , hpos , it - > first ) ) ;
nnn - > id = map - > objects . size ( ) ;
nnn - > initHero ( ) ;
map - > heroes . push_back ( nnn ) ;
map - > objects . push_back ( nnn ) ;
map - > addBlockVisTiles ( nnn ) ;
2012-09-24 22:23:11 +03:00
}
2008-07-27 20:07:37 +03:00
}
}
2012-11-11 00:56:19 +03:00
2010-08-30 17:52:18 +03:00
/*************************replace hero placeholders*****************************/
2012-09-22 18:16:45 +03:00
tlog4 < < " \t Replacing hero placeholders " ;
2012-09-21 20:59:54 +03:00
if ( scenarioOps - > campState )
2010-08-30 17:52:18 +03:00
{
2012-09-21 20:59:54 +03:00
auto campaign = scenarioOps - > campState ;
2012-09-24 22:23:11 +03:00
auto bonus = campaign - > getBonusForCurrentMap ( ) ;
2010-09-04 17:49:15 +03:00
2012-09-24 22:23:11 +03:00
if ( bonus . is_initialized ( ) )
2010-09-04 17:49:15 +03:00
{
2012-09-24 22:23:11 +03:00
std : : vector < CGHeroInstance * > Xheroes ;
if ( bonus - > type = = CScenarioTravel : : STravelBonus : : PLAYER_PREV_SCENARIO )
2010-08-30 17:52:18 +03:00
{
2012-09-24 22:23:11 +03:00
Xheroes = campaign - > camp - > scenarios [ bonus - > info2 ] . crossoverHeroes ;
2010-08-30 17:52:18 +03:00
}
2012-09-24 22:23:11 +03:00
//selecting heroes by type
for ( int g = 0 ; g < map - > objects . size ( ) ; + + g )
2010-08-30 17:52:18 +03:00
{
2012-09-24 22:23:11 +03:00
CGObjectInstance * obj = map - > objects [ g ] ;
if ( obj - > ID ! = Obj : : HERO_PLACEHOLDER )
2010-08-30 17:52:18 +03:00
{
2012-09-24 22:23:11 +03:00
continue ;
2010-08-30 17:52:18 +03:00
}
2012-09-24 22:23:11 +03:00
CGHeroPlaceholder * hp = static_cast < CGHeroPlaceholder * > ( obj ) ;
if ( hp - > subID ! = 0xFF ) //select by type
2010-09-04 17:49:15 +03:00
{
2012-09-24 22:23:11 +03:00
bool found = false ;
BOOST_FOREACH ( CGHeroInstance * ghi , Xheroes )
{
if ( ghi - > subID = = hp - > subID )
{
found = true ;
replaceHero ( g , ghi ) ;
Xheroes - = ghi ;
break ;
}
}
if ( ! found )
{
//TODO: create new hero of this type
}
2010-09-04 17:49:15 +03:00
}
}
2012-09-24 22:23:11 +03:00
//selecting heroes by power
2010-09-04 17:49:15 +03:00
2012-09-24 22:23:11 +03:00
std : : sort ( Xheroes . begin ( ) , Xheroes . end ( ) , [ ] ( const CGHeroInstance * a , const CGHeroInstance * b )
2012-09-22 18:16:45 +03:00
{
return a - > getHeroStrength ( ) > b - > getHeroStrength ( ) ;
} ) ; //sort, descending strength
2012-09-24 22:23:11 +03:00
for ( int g = 0 ; g < map - > objects . size ( ) ; + + g )
2010-09-04 17:49:15 +03:00
{
2012-09-24 22:23:11 +03:00
CGObjectInstance * obj = map - > objects [ g ] ;
if ( obj - > ID ! = Obj : : HERO_PLACEHOLDER )
{
continue ;
}
CGHeroPlaceholder * hp = static_cast < CGHeroPlaceholder * > ( obj ) ;
2010-09-04 17:49:15 +03:00
2012-09-24 22:23:11 +03:00
if ( hp - > subID = = 0xFF ) //select by power
{
if ( Xheroes . size ( ) > hp - > power - 1 )
replaceHero ( g , Xheroes [ hp - > power - 1 ] ) ;
else
tlog2 < < " Warning, to hero to replace! \n " ;
//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
}
}
2012-11-11 00:56:19 +03:00
2010-08-30 17:52:18 +03:00
}
2008-06-30 03:06:41 +03:00
/******************RESOURCES****************************************************/
2012-09-22 18:16:45 +03:00
tlog4 < < " \t Setting up resources " ;
2012-08-02 14:03:26 +03:00
const JsonNode config ( ResourceID ( " config/startres.json " ) ) ;
2011-08-20 05:53:57 +03:00
const JsonVector & vector = config [ " difficulty " ] . Vector ( ) ;
const JsonNode & level = vector [ scenarioOps - > difficulty ] ;
2012-09-02 13:33:41 +03:00
TResources startresAI ( level [ " ai " ] ) ;
TResources startresHuman ( level [ " human " ] ) ;
2011-07-05 09:14:07 +03:00
2012-09-24 19:14:53 +03:00
for ( auto 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-09-24 22:23:11 +03:00
auto chosenBonus = scenarioOps - > campState - > getBonusForCurrentMap ( ) ;
if ( chosenBonus . is_initialized ( ) & & chosenBonus - > type = = CScenarioTravel : : STravelBonus : : RESOURCE )
2010-07-31 16:55:05 +03:00
{
2012-09-22 18:16:45 +03:00
std : : vector < const PlayerSettings * > people = getHumanPlayerInfo ( ) ; //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
2012-09-24 22:23:11 +03:00
switch ( chosenBonus - > info1 )
2010-07-31 16:55:05 +03:00
{
case 0 : case 1 : case 2 : case 3 : case 4 : case 5 : case 6 :
2012-09-24 22:23:11 +03:00
res . push_back ( chosenBonus - > info1 ) ;
2010-07-31 16:55:05 +03:00
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 )
{
2012-09-24 22:23:11 +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************************************************/
2012-09-22 18:16:45 +03:00
tlog4 < < " \t Setting up 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
{
2012-09-23 21:01:04 +03:00
if ( map - > objects [ i ] - > ID = = Obj : : PRISON )
2010-02-10 23:31:54 +02:00
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
{
2012-11-06 19:39:29 +03:00
hpool . pavailable [ map - > disposedHeroes [ i ] . heroId ] = 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-09-24 22:23:11 +03:00
auto chosenBonus = scenarioOps - > campState - > getBonusForCurrentMap ( ) ;
if ( chosenBonus . is_initialized ( ) & & chosenBonus - > isBonusForHero ( ) & & chosenBonus - > info1 ! = 0xFFFE ) //exclude generated heroes
2010-08-01 15:52:42 +03:00
{
//find human player
2012-07-06 23:19:54 +03:00
int humanPlayer = GameConstants : : NEUTRAL_PLAYER ;
2012-09-24 19:14:53 +03:00
for ( auto it = players . begin ( ) ; it ! = players . end ( ) ; + + it )
2010-08-01 15:52:42 +03:00
{
if ( it - > second . human )
{
humanPlayer = it - > first ;
break ;
}
}
2012-07-06 23:19:54 +03:00
assert ( humanPlayer ! = GameConstants : : NEUTRAL_PLAYER ) ;
2010-12-20 15:04:24 +02:00
std : : vector < ConstTransitivePtr < CGHeroInstance > > & heroes = players [ humanPlayer ] . heroes ;
2010-08-01 15:52:42 +03:00
2012-09-24 22:23:11 +03:00
if ( chosenBonus - > info1 = = 0xFFFD ) //most powerful
2010-08-01 15:52:42 +03:00
{
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-09-22 18:16:45 +03:00
giveCampaignBonusToHero ( heroes [ maxB ] ) ;
2010-08-01 15:52:42 +03:00
}
else //specific hero
{
for ( int b = 0 ; b < heroes . size ( ) ; + + b )
{
2012-09-24 22:23:11 +03:00
if ( heroes [ b ] - > subID = = chosenBonus - > info1 )
2010-08-01 15:52:42 +03:00
{
2012-09-22 18:16:45 +03:00
giveCampaignBonusToHero ( heroes [ b ] ) ;
2010-08-01 15:52:42 +03:00
break ;
}
}
}
}
}
2010-08-03 15:34:06 +03:00
/*************************FOG**OF**WAR******************************************/
2012-09-22 18:16:45 +03:00
tlog4 < < " \t Fog of war " ;
2012-09-24 19:14:53 +03:00
for ( auto 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 )
2012-11-20 20:53:45 +03:00
k - > second . fogOfWarMap [ g ] [ h ] . resize ( map - > twoLevel ? 2 : 1 , 0 ) ;
2008-06-30 03:06:41 +03:00
for ( int g = 0 ; g < map - > width ; + + g )
for ( int h = 0 ; h < map - > height ; + + h )
2012-11-20 20:53:45 +03:00
for ( int v = 0 ; v < ( map - > twoLevel ? 2 : 1 ) ; + + v )
2008-06-30 03:06:41 +03:00
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
2012-09-22 18:16:45 +03:00
tlog4 < < " \t Starting bonuses " ;
2012-09-24 19:14:53 +03:00
for ( auto k = players . begin ( ) ; k ! = players . end ( ) ; + + k )
2010-08-03 15:34:06 +03:00
{
2008-08-26 00:14:00 +03:00
//starting bonus
2012-12-02 15:21:44 +03:00
if ( scenarioOps - > playerInfos [ k - > first ] . bonus = = PlayerSettings : : RANDOM )
2013-02-02 01:04:25 +03:00
scenarioOps - > playerInfos [ k - > first ] . bonus = static_cast < PlayerSettings : : Ebonus > ( ran ( ) % 3 ) ;
2010-10-24 14:35:14 +03:00
switch ( scenarioOps - > playerInfos [ k - > first ] . bonus )
2008-08-26 00:14:00 +03:00
{
2012-12-02 15:21:44 +03:00
case PlayerSettings : : GOLD :
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 ;
2012-12-02 15:21:44 +03:00
case PlayerSettings : : RESOURCE :
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 ;
}
2012-12-02 15:21:44 +03:00
case PlayerSettings : : ARTIFACT :
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************************************************/
2012-09-22 18:16:45 +03:00
tlog4 < < " \t Towns " ;
2012-12-13 16:07:56 +03:00
CGTownInstance : : universitySkills . clear ( ) ;
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
2012-10-05 16:11:26 +03: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 ) ;
2012-09-05 15:49:23 +03:00
vti - > builtBuildings . insert ( EBuilding : : VILLAGE_HALL ) ;
vti - > builtBuildings . insert ( EBuilding : : TAVERN ) ;
vti - > builtBuildings . insert ( EBuilding : : DWELL_FIRST ) ;
2008-06-30 03:06:41 +03:00
if ( ran ( ) % 2 )
2012-09-05 15:49:23 +03:00
vti - > builtBuildings . insert ( EBuilding : : DWELL_FIRST + 1 ) ;
2010-06-30 22:27:35 +03:00
}
2012-02-16 20:10:58 +03:00
2012-09-23 21:01:04 +03:00
if ( vstd : : contains ( vti - > builtBuildings , EBuilding : : SHIPYARD ) & & vti - > state ( ) = = IBoatGenerator : : TILE_BLOCKED )
2012-09-05 15:49:23 +03:00
vti - > builtBuildings . erase ( EBuilding : : SHIPYARD ) ; //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
{
2012-09-05 15:49:23 +03:00
vti - > builtBuildings . insert ( EBuilding : : HORDE_1 ) ; //add it
if ( vstd : : contains ( vti - > builtBuildings , ( EBuilding : : DWELL_UP_FIRST + i ) ) ) //if we have upgraded dwelling as well
vti - > builtBuildings . insert ( EBuilding : : HORDE_1_UPGR ) ; //add it as well
2010-02-13 17:56:34 +02:00
}
if ( vti - > town - > hordeLvl [ 1 ] = = i ) //if town second horde is this one
{
2012-09-05 15:49:23 +03:00
vti - > builtBuildings . insert ( EBuilding : : HORDE_2 ) ;
if ( vstd : : contains ( vti - > builtBuildings , ( EBuilding : : DWELL_UP_FIRST + i ) ) )
vti - > builtBuildings . insert ( EBuilding : : HORDE_2_UPGR ) ;
2010-02-13 17:56:34 +02:00
}
}
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 )
2012-09-05 15:49:23 +03:00
ev - > buildings . insert ( EBuilding : : HORDE_1 ) ;
2010-08-25 17:57:58 +03:00
if ( vti - > town - > hordeLvl [ 1 ] = = i )
2012-09-05 15:49:23 +03:00
ev - > buildings . insert ( EBuilding : : HORDE_2 ) ;
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 ] ;
2012-12-18 13:32:11 +03:00
if ( total = = 0 ) // remaining spells have 0 probability
break ;
int r = ran ( ) % total ;
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 ;
}
2012-12-18 13:32:11 +03:00
vti - > possibleSpells . clear ( ) ;
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-09-24 22:23:11 +03:00
auto chosenBonus = scenarioOps - > campState - > getBonusForCurrentMap ( ) ;
2010-08-02 17:29:30 +03:00
2012-09-24 22:23:11 +03:00
if ( chosenBonus . is_initialized ( ) & & chosenBonus - > type = = CScenarioTravel : : STravelBonus : : BUILDING )
2010-08-02 17:29:30 +03:00
{
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 (
2012-09-24 22:23:11 +03:00
CBuildingHandler : : campToERMU ( chosenBonus - > info1 , map - > towns [ g ] - > town - > typeID , map - > towns [ g ] - > builtBuildings ) ) ;
2012-02-16 20:10:58 +03:00
break ;
}
2010-08-02 17:29:30 +03:00
}
}
}
}
2012-09-22 18:16:45 +03:00
tlog4 < < " \t Object initialization " ;
2011-02-04 16:58:14 +02:00
objCaller - > preInit ( ) ;
BOOST_FOREACH ( CGObjectInstance * obj , map - > objects )
{
obj - > initObj ( ) ;
2012-09-23 21:01:04 +03:00
if ( obj - > ID = = Obj : : PRISON ) //prison also needs to initialize hero
2011-02-04 16:58:14 +02:00
static_cast < CGHeroInstance * > ( obj ) - > initHero ( ) ;
}
2012-07-19 12:10:55 +03:00
BOOST_FOREACH ( CGObjectInstance * obj , map - > objects )
{
switch ( obj - > ID )
{
case Obj : : QUEST_GUARD :
case Obj : : SEER_HUT :
{
auto q = static_cast < CGSeerHut * > ( obj ) ;
assert ( q ) ;
q - > setObjToKill ( ) ;
}
}
}
2011-02-04 16:58:14 +02:00
CGTeleport : : postInit ( ) ; //pairing subterranean gates
buildBonusSystemTree ( ) ;
2012-09-24 19:14:53 +03:00
for ( auto 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
2012-09-22 18:16:45 +03:00
tlog4 < < " \t Checking objectives " ;
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)
2012-11-11 00:56:19 +03:00
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-07-26 03:48:44 +03:00
void CGameState : : initDuel ( )
{
DuelParameters dp ;
try //CLoadFile likes throwing
{
if ( boost : : algorithm : : ends_with ( scenarioOps - > mapname , " .json " ) )
{
tlog0 < < " Loading duel settings from JSON file: " < < scenarioOps - > mapname < < std : : endl ;
dp = DuelParameters : : fromJSON ( scenarioOps - > mapname ) ;
tlog0 < < " JSON file has been successfully read! \n " ;
}
else
{
CLoadFile lf ( scenarioOps - > mapname ) ;
lf > > dp ;
}
}
catch ( . . . )
{
tlog1 < < " Cannot load duel settings from " < < scenarioOps - > mapname < < std : : endl ;
throw ;
}
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 )
{
const DuelParameters : : SideSettings & ss = dp . sides [ i ] ;
CGHeroInstance * h = new CGHeroInstance ( ) ;
armies [ i ] = heroes [ i ] = h ;
obj = h ;
h - > subID = ss . heroId ;
for ( int i = 0 ; i < ss . heroPrimSkills . size ( ) ; i + + )
h - > pushPrimSkill ( i , ss . heroPrimSkills [ i ] ) ;
if ( ss . spells . size ( ) )
{
h - > putArtifact ( ArtifactPosition : : SPELLBOOK , CArtifactInstance : : createNewArtifactInstance ( 0 ) ) ;
boost : : copy ( ss . spells , std : : inserter ( h - > spells , h - > spells . begin ( ) ) ) ;
}
BOOST_FOREACH ( auto & parka , ss . artifacts )
{
h - > putArtifact ( parka . first , parka . second ) ;
}
typedef const std : : pair < si32 , si8 > & TSecSKill ;
BOOST_FOREACH ( TSecSKill secSkill , ss . heroSecSkills )
h - > setSecSkillLevel ( ( CGHeroInstance : : SecondarySkill ) secSkill . first , secSkill . second , 1 ) ;
h - > initHero ( h - > subID ) ;
obj - > initObj ( ) ;
}
else
{
CGCreature * c = new CGCreature ( ) ;
armies [ i ] = obj = c ;
//c->subID = 34;
}
obj - > setOwner ( i ) ;
for ( int j = 0 ; j < ARRAY_COUNT ( dp . sides [ i ] . stacks ) ; j + + )
{
TCreature cre = dp . sides [ i ] . stacks [ j ] . type ;
TQuantity count = dp . sides [ i ] . stacks [ j ] . count ;
if ( count | | obj - > hasStackAtSlot ( j ) )
obj - > setCreature ( j , cre , count ) ;
}
BOOST_FOREACH ( const DuelParameters : : CusomCreature & cc , dp . creatures )
{
CCreature * c = VLC - > creh - > creatures [ cc . id ] ;
if ( cc . attack > = 0 )
2012-09-20 19:55:21 +03:00
c - > getBonusLocalFirst ( Selector : : typeSubtype ( Bonus : : PRIMARY_SKILL , PrimarySkill : : ATTACK ) ) - > val = cc . attack ;
2012-07-26 03:48:44 +03:00
if ( cc . defense > = 0 )
2012-09-20 19:55:21 +03:00
c - > getBonusLocalFirst ( Selector : : typeSubtype ( Bonus : : PRIMARY_SKILL , PrimarySkill : : DEFENSE ) ) - > val = cc . defense ;
2012-07-26 03:48:44 +03:00
if ( cc . speed > = 0 )
2012-09-20 19:55:21 +03:00
c - > getBonusLocalFirst ( Selector : : type ( Bonus : : STACKS_SPEED ) ) - > val = cc . speed ;
2012-07-26 03:48:44 +03:00
if ( cc . HP > = 0 )
2012-09-20 19:55:21 +03:00
c - > getBonusLocalFirst ( Selector : : type ( Bonus : : STACK_HEALTH ) ) - > val = cc . HP ;
2012-07-26 03:48:44 +03:00
if ( cc . dmg > = 0 )
{
2012-09-20 19:55:21 +03:00
c - > getBonusLocalFirst ( Selector : : typeSubtype ( Bonus : : CREATURE_DAMAGE , 1 ) ) - > val = cc . dmg ;
c - > getBonusLocalFirst ( Selector : : typeSubtype ( Bonus : : CREATURE_DAMAGE , 2 ) ) - > val = cc . dmg ;
2012-07-26 03:48:44 +03:00
}
if ( cc . shoots > = 0 )
2012-09-20 19:55:21 +03:00
c - > getBonusLocalFirst ( Selector : : type ( Bonus : : SHOTS ) ) - > val = cc . shoots ;
2012-07-26 03:48:44 +03:00
}
}
curB = BattleInfo : : setupBattle ( int3 ( ) , dp . bfieldType , dp . terType , armies , heroes , false , town ) ;
curB - > obstacles = dp . obstacles ;
curB - > localInit ( ) ;
return ;
}
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
2012-11-06 19:39:29 +03:00
switch ( t . terType )
2009-02-10 16:21:51 +02:00
{
2012-10-26 20:51:05 +03:00
case ETerrainType : : DIRT :
2009-02-10 16:21:51 +02:00
return rand ( ) % 3 + 3 ;
2012-10-26 20:51:05 +03:00
case ETerrainType : : SAND :
2009-02-10 16:21:51 +02:00
return 2 ; //TODO: coast support
2012-10-26 20:51:05 +03:00
case ETerrainType : : GRASS :
2009-02-10 16:21:51 +02:00
return rand ( ) % 2 + 6 ;
2012-10-26 20:51:05 +03:00
case ETerrainType : : SNOW :
2009-02-10 16:21:51 +02:00
return rand ( ) % 2 + 10 ;
2012-10-26 20:51:05 +03:00
case ETerrainType : : SWAMP :
2009-02-10 16:21:51 +02:00
return 13 ;
2012-10-26 20:51:05 +03:00
case ETerrainType : : ROUGH :
2009-02-10 16:21:51 +02:00
return 23 ;
2012-10-26 20:51:05 +03:00
case ETerrainType : : SUBTERRANEAN :
2009-02-10 16:21:51 +02:00
return 12 ;
2012-10-26 20:51:05 +03:00
case ETerrainType : : LAVA :
2009-02-10 16:21:51 +02:00
return 8 ;
2012-10-26 20:51:05 +03:00
case ETerrainType : : WATER :
2009-02-10 16:21:51 +02:00
return 25 ;
2012-10-26 20:51:05 +03:00
case ETerrainType : : ROCK :
2009-02-10 16:21:51 +02:00
return 15 ;
default :
return - 1 ;
}
2009-02-09 16:50:32 +02:00
}
2010-07-15 06:04:57 +03:00
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 ;
2012-09-23 21:01:04 +03:00
const CGHeroInstance * h = stack . armyObj - > ID = = Obj : : HERO ? static_cast < const CGHeroInstance * > ( stack . armyObj ) : NULL ;
2010-07-15 06:04:57 +03:00
const CGTownInstance * t = NULL ;
2012-09-23 21:01:04 +03:00
if ( stack . armyObj - > ID = = Obj : : TOWN )
2010-07-15 06:04:57 +03:00
t = static_cast < const CGTownInstance * > ( stack . armyObj ) ;
else if ( h )
2013-01-17 21:15:00 +03:00
{ //hero specialty
TBonusListPtr lista = h - > 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 ;
}
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
2012-11-06 19:39:29 +03:00
if ( srct . terType = = ETerrainType : : WATER & & limitCoastSailing & & hlpt . terType = = ETerrainType : : WATER & & dirs [ i ] . x & & dirs [ i ] . y ) //diagonal move through water
2010-07-10 05:15:49 +03:00
{
int3 hlp1 = tile ,
hlp2 = tile ;
hlp1 . x + = dirs [ i ] . x ;
hlp2 . y + = dirs [ i ] . y ;
2012-11-06 19:39:29 +03:00
if ( map - > getTile ( hlp1 ) . terType ! = ETerrainType : : WATER | | map - > getTile ( hlp2 ) . terType ! = ETerrainType : : WATER )
2010-07-10 05:15:49 +03:00
continue ;
}
2012-11-06 19:39:29 +03:00
if ( ( indeterminate ( onLand ) | | onLand = = ( hlpt . terType ! = ETerrainType : : WATER ) )
& & hlpt . terType ! = ETerrainType : : 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
}
}
2012-11-06 19:39:29 +03:00
else if ( d . terType = = ETerrainType : : WATER )
2010-05-15 18:00:19 +03:00
{
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 ;
2012-11-06 19:39:29 +03:00
getNeighbours ( d , dest , vec , s . terType ! = ETerrainType : : 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 .
*/
2012-11-15 00:19:32 +03:00
std : : vector < CGObjectInstance * > CGameState : : guardingCreatures ( int3 pos ) const
2012-11-14 17:27:18 +03:00
{
std : : vector < CGObjectInstance * > guards ;
const int3 originalPos = pos ;
if ( ! map - > isInTheMap ( pos ) )
return guards ;
const TerrainTile & posTile = map - > terrain [ pos . x ] [ pos . y ] [ pos . z ] ;
if ( posTile . visitable )
{
BOOST_FOREACH ( CGObjectInstance * obj , posTile . visitableObjects )
{
if ( obj - > blockVisit )
{
2013-01-15 17:20:48 +03:00
if ( obj - > ID = = Obj : : MONSTER ) // Monster
2012-11-14 17:27:18 +03:00
guards . push_back ( obj ) ;
}
}
}
pos - = int3 ( 1 , 1 , 0 ) ; // Start with top left.
for ( int dx = 0 ; dx < 3 ; dx + + )
{
for ( int dy = 0 ; dy < 3 ; dy + + )
{
if ( map - > isInTheMap ( pos ) )
{
TerrainTile & tile = map - > terrain [ pos . x ] [ pos . y ] [ pos . z ] ;
2013-01-15 17:20:48 +03:00
if ( tile . visitable & & ( tile . isWater ( ) = = posTile . isWater ( ) ) )
2012-11-14 17:27:18 +03:00
{
BOOST_FOREACH ( CGObjectInstance * obj , tile . visitableObjects )
{
2013-01-15 17:20:48 +03:00
if ( obj - > ID = = Obj : : MONSTER & & checkForVisitableDir ( pos , & map - > getTile ( originalPos ) , originalPos ) ) // Monster being able to attack investigated tile
2012-11-14 17:27:18 +03:00
{
guards . push_back ( obj ) ;
}
}
}
}
pos . y + + ;
}
pos . y - = 3 ;
pos . x + + ;
}
return guards ;
}
2010-05-06 15:13:31 +03:00
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 )
{
2013-01-15 17:20:48 +03:00
if ( obj - > ID = = Obj : : MONSTER ) // Monster
2010-05-27 00:59:58 +03:00
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 ] ;
2013-01-15 17:20:48 +03:00
if ( tile . visitable & & ( tile . isWater ( ) = = posTile . isWater ( ) ) )
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
{
2013-01-15 17:20:48 +03:00
if ( obj - > ID = = Obj : : MONSTER & & 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...
2012-09-21 20:59:54 +03:00
if ( map - > victoryCondition . condition = = EVictoryConditionType : : WINSTANDARD )
return - 1 ;
else
return 1 ;
2010-07-30 14:29:42 +03:00
}
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 + + )
2012-11-06 19:39:29 +03:00
if ( p - > heroes [ i ] - > hasArt ( map - > victoryCondition . objectId ) )
2010-01-29 22:52:45 +02:00
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
2012-11-06 19:39:29 +03:00
if ( i - > second - > type - > idNumber = = map - > victoryCondition . objectId ) //it's searched creature
2010-11-22 02:34:46 +02:00
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 :
2012-11-06 19:39:29 +03:00
if ( p - > resources [ map - > victoryCondition . objectId ] > = map - > victoryCondition . count )
2010-01-29 22:52:45 +02:00
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 ) ;
2012-11-06 19:39:29 +03:00
if ( t - > tempOwner = = player & & t - > fortLevel ( ) - 1 > = map - > victoryCondition . objectId & & 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-09-05 15:49:23 +03:00
& & t - > hasBuilt ( 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 ) ;
2012-11-06 19:39:29 +03:00
if ( ( t - > visitingHero & & t - > visitingHero - > hasArt ( map - > victoryCondition . objectId ) )
| | ( t - > garrisonHero & & t - > garrisonHero - > hasArt ( map - > victoryCondition . objectId ) ) )
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
2012-09-24 19:14:53 +03:00
TPlayerColor supposedWinner = 255 , winnerTeam = 255 ;
for ( auto i = players . begin ( ) ; i ! = players . end ( ) ; i + + )
2010-01-29 22:52:45 +02:00
{
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
{
2012-09-24 19:14:53 +03:00
typedef std : : pair < TPlayerColor , si64 > TStat ;
2010-02-11 21:18:30 +02:00
//converts [<player's color, value>] to vec[place] -> platers
2012-09-24 19:14:53 +03:00
static std : : vector < std : : vector < TPlayerColor > > 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
2012-09-24 19:14:53 +03:00
std : : vector < std : : vector < TPlayerColor > > ret ;
std : : vector < TPlayerColor > tmp ;
2010-02-11 21:18:30 +02:00
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
2012-09-24 19:14:53 +03:00
std : : vector < TPlayerColor > tmp ;
2010-02-11 21:18:30 +02:00
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
}
2012-11-11 00:56:19 +03: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 ;
2012-11-11 00:56:19 +03:00
BOOST_FOREACH ( auto h , ps - > heroes )
2010-02-06 15:49:14 +02:00
{
2012-11-11 00:56:19 +03:00
ret + = h - > artifactsInBackpack . size ( ) + h - > artifactsWorn . size ( ) ;
2010-02-06 15:49:14 +02:00
}
2010-02-11 21:18:30 +02:00
return ret ;
}
2012-11-11 00:56:19 +03:00
// get total strength of player army
static si64 getArmyStrength ( const PlayerState * ps )
{
si64 str = 0 ;
BOOST_FOREACH ( auto h , ps - > heroes )
{
if ( ! h - > inTownGarrison ) //original h3 behavior
str + = h - > getArmyStrength ( ) ;
}
return str ;
}
2010-02-11 21:18:30 +02:00
} ;
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) \
{ \
2012-09-24 19:14:53 +03:00
std : : vector < std : : pair < TPlayerColor , si64 > > stats ; \
for ( auto g = players . begin ( ) ; g ! = players . end ( ) ; + + g ) \
2010-02-01 19:51:33 +02:00
{ \
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
}
2012-09-24 19:14:53 +03:00
for ( auto g = players . begin ( ) ; g ! = players . end ( ) ; + + g )
2010-02-01 19:51:33 +02:00
{
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
2012-09-24 19:14:53 +03:00
for ( auto g = players . cbegin ( ) ; g ! = players . cend ( ) ; + + g )
2010-02-04 20:40:40 +02:00
{
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
{
2013-01-15 17:20:48 +03:00
//TODO: obtainPlayersStats - obelisks found
2010-02-01 19:51:33 +02:00
}
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
{
2012-11-11 00:56:19 +03:00
FILL_FIELD ( army , statsHLP : : getArmyStrength ( & g - > second ) )
2010-02-01 19:51:33 +02:00
}
if ( level > = 7 ) //income
{
2013-01-15 17:20:48 +03:00
//TODO:obtainPlayersStats - income
2010-02-01 19:51:33 +02:00
}
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
{
2012-09-24 19:14:53 +03:00
for ( auto g = players . cbegin ( ) ; g ! = players . cend ( ) ; + + g )
2010-02-06 15:49:14 +02:00
{
if ( g - > second . color = = 255 ) //do nothing for neutral player
continue ;
if ( g - > second . human )
{
2012-11-06 19:39:29 +03:00
tgi . personality [ g - > second . color ] = EAiTactic : : NONE ;
2010-02-06 15:49:14 +02:00
}
else //AI
{
2012-11-06 19:39:29 +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)
2012-09-24 19:14:53 +03:00
for ( auto g = players . cbegin ( ) ; g ! = players . cend ( ) ; + + g )
2010-02-06 15:49:14 +02:00
{
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 :
case ELossConditionType : : LOSSHERO :
2010-01-29 22:52:45 +02:00
{
2013-01-15 17:20:48 +03:00
const CGObjectInstance * obj = map - > lossCondition . obj ;
assert ( obj ) ;
if ( obj - > tempOwner ! = player )
2010-01-29 22:52:45 +02:00
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 ;
2012-09-24 19:14:53 +03:00
for ( auto i = players . cbegin ( ) ; i ! = players . cend ( ) ; i + + )
for ( auto j = i - > second . availableHeroes . cbegin ( ) ; j ! = i - > second . availableHeroes . cend ( ) ; 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
{
2012-09-24 19:14:53 +03:00
for ( auto k = teams . begin ( ) ; k ! = teams . end ( ) ; + + k )
2011-02-04 16:58:14 +02:00
{
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 )
2013-01-20 23:29:35 +03:00
: details ( nullptr ) ,
hclass ( nullptr ) ,
portrait ( - 1 )
2012-06-13 16:04:06 +03:00
{
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 ( ) ;
2012-09-05 15:49:23 +03:00
details - > customRes = t - > hasBuilt ( EBuilding : : RESOURCE_SILO ) ;
2012-06-13 16:04:06 +03:00
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 ( )
{
2012-10-26 20:51:05 +03:00
terType = ETerrainType : : DIRT ;
2011-01-21 04:36:30 +02:00
bfieldType = 15 ;
2011-02-06 19:26:27 +02:00
}
2011-02-21 06:13:00 +02:00
2012-07-26 03:48:44 +03:00
DuelParameters DuelParameters : : fromJSON ( const std : : string & fname )
{
DuelParameters ret ;
2012-09-20 19:55:21 +03:00
const JsonNode duelData ( ResourceID ( " DATA/ " + fname , EResType : : TEXT ) ) ;
2012-07-26 03:48:44 +03:00
ret . terType = duelData [ " terType " ] . Float ( ) ;
ret . bfieldType = duelData [ " bfieldType " ] . Float ( ) ;
BOOST_FOREACH ( const JsonNode & n , duelData [ " sides " ] . Vector ( ) )
{
SideSettings & ss = ret . sides [ ( int ) n [ " side " ] . Float ( ) ] ;
int i = 0 ;
BOOST_FOREACH ( const JsonNode & stackNode , n [ " army " ] . Vector ( ) )
{
ss . stacks [ i ] . type = stackNode . Vector ( ) [ 0 ] . Float ( ) ;
ss . stacks [ i ] . count = stackNode . Vector ( ) [ 1 ] . Float ( ) ;
i + + ;
}
if ( n [ " heroid " ] . getType ( ) = = JsonNode : : DATA_FLOAT )
ss . heroId = n [ " heroid " ] . Float ( ) ;
else
ss . heroId = - 1 ;
BOOST_FOREACH ( const JsonNode & n , n [ " heroPrimSkills " ] . Vector ( ) )
ss . heroPrimSkills . push_back ( n . Float ( ) ) ;
BOOST_FOREACH ( const JsonNode & skillNode , n [ " heroSecSkills " ] . Vector ( ) )
{
std : : pair < si32 , si8 > secSkill ;
secSkill . first = skillNode . Vector ( ) [ 0 ] . Float ( ) ;
secSkill . second = skillNode . Vector ( ) [ 1 ] . Float ( ) ;
ss . heroSecSkills . push_back ( secSkill ) ;
}
assert ( ss . heroPrimSkills . empty ( ) | | ss . heroPrimSkills . size ( ) = = GameConstants : : PRIMARY_SKILLS ) ;
if ( ss . heroId ! = - 1 )
2012-08-01 15:02:54 +03:00
{
2012-09-22 18:10:15 +03:00
const JsonNode & spells = n [ " spells " ] ;
2012-09-20 19:55:21 +03:00
if ( spells . getType ( ) = = JsonNode : : DATA_STRING & & spells . String ( ) = = " all " )
2012-09-24 02:10:56 +03:00
{
2012-09-20 19:55:21 +03:00
BOOST_FOREACH ( auto spell , VLC - > spellh - > spells )
2012-11-11 00:56:19 +03:00
if ( spell - > id < = Spells : : SUMMON_AIR_ELEMENTAL )
2012-09-24 02:10:56 +03:00
ss . spells . insert ( spell - > id ) ;
}
2012-09-20 19:55:21 +03:00
else
BOOST_FOREACH ( const JsonNode & spell , n [ " spells " ] . Vector ( ) )
ss . spells . insert ( spell . Float ( ) ) ;
2012-08-01 15:02:54 +03:00
}
2012-07-26 03:48:44 +03:00
}
BOOST_FOREACH ( const JsonNode & n , duelData [ " obstacles " ] . Vector ( ) )
{
auto oi = make_shared < CObstacleInstance > ( ) ;
if ( n . getType ( ) = = JsonNode : : DATA_VECTOR )
{
oi - > ID = n . Vector ( ) [ 0 ] . Float ( ) ;
oi - > pos = n . Vector ( ) [ 1 ] . Float ( ) ;
}
else
{
assert ( n . getType ( ) = = JsonNode : : DATA_FLOAT ) ;
oi - > ID = 21 ;
oi - > pos = n . Float ( ) ;
}
oi - > uniqueID = ret . obstacles . size ( ) ;
ret . obstacles . push_back ( oi ) ;
}
BOOST_FOREACH ( const JsonNode & n , duelData [ " creatures " ] . Vector ( ) )
{
CusomCreature cc ;
cc . id = n [ " id " ] . Float ( ) ;
# define retreive(name) \
if ( n [ # name ] . getType ( ) = = JsonNode : : DATA_FLOAT ) \
cc . name = n [ # name ] . Float ( ) ; \
else \
cc . name = - 1 ;
retreive ( attack ) ;
retreive ( defense ) ;
retreive ( HP ) ;
retreive ( dmg ) ;
retreive ( shoots ) ;
retreive ( speed ) ;
ret . creatures . push_back ( cc ) ;
}
return ret ;
}
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 ;
2012-11-06 19:39:29 +03:00
node . land = tinfo - > terType ! = ETerrainType : : WATER ;
2011-09-19 23:50:25 +03:00
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
2012-11-06 19:39:29 +03:00
bool subterraneanEntry = ( ct - > topVisitableId ( ) = = Obj : : SUBTERRANEAN_GATE & & 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 ) ;
2012-11-06 19:39:29 +03:00
destTopVisObjID = dt - > topVisitableId ( ) ;
2011-09-19 23:50:25 +03:00
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
2012-11-06 19:39:29 +03:00
if ( cp - > accessible = = CGPathNode : : VISITABLE & & guardedSource & & cp - > theNodeBefore - > land & & ct - > topVisitableId ( ) = = Obj : : BOAT )
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
2012-09-23 21:01:04 +03:00
if ( subterraneanEntry & & destTopVisObjID = = Obj : : SUBTERRANEAN_GATE & & 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 )
2012-09-23 21:01:04 +03:00
| | destTopVisObjID = = Obj : : SUBTERRANEAN_GATE
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 ) ;
}
CGPathNode : : EAccessibility CPathfinder : : evaluateAccessibility ( const TerrainTile * tinfo ) const
{
CGPathNode : : EAccessibility ret = ( tinfo - > blocked ? CGPathNode : : BLOCKED : CGPathNode : : ACCESSIBLE ) ;
2012-11-06 19:39:29 +03:00
if ( tinfo - > terType = = ETerrainType : : ROCK | | ! FoW [ curPos . x ] [ curPos . y ] [ curPos . z ] )
2011-09-19 23:50:25 +03:00
return CGPathNode : : BLOCKED ;
2012-02-16 20:10:58 +03:00
2011-09-19 23:50:25 +03:00
if ( tinfo - > visitable )
{
2013-01-15 17:20:48 +03:00
if ( tinfo - > visitableObjects . front ( ) - > ID = = Obj : : SANCTUARY & & tinfo - > visitableObjects . back ( ) - > ID = = Obj : : HERO & & 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 ;
}
2012-09-23 21:01:04 +03:00
else if ( obj - > ID ! = Obj : : EVENT ) //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 ;
2012-09-23 21:01:04 +03:00
if ( destTopVisObjID ! = Obj : : HERO & & destTopVisObjID ! = Obj : : BOAT ) //only boat or hero can be accessed from land
2011-09-19 23:50:25 +03:00
return false ;
2012-09-23 21:01:04 +03:00
if ( destTopVisObjID = = Obj : : BOAT )
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
}