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
2013-04-07 13:48:07 +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-04-07 13:48:07 +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-04-07 13:48:07 +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"
2013-07-28 17:49:50 +03:00
# include "filesystem/Filesystem.h"
2011-12-14 00:23:17 +03:00
# include "GameConstants.h"
2013-04-07 13:48:07 +03:00
# include "rmg/CMapGenerator.h"
2013-04-29 18:51:39 +03:00
# include "CStopWatch.h"
2009-07-09 22:15:22 +03:00
2013-06-26 14:18:27 +03:00
DLL_LINKAGE std : : minstd_rand 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
*
*/
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 ( ) { } ;
2013-06-26 14:18:27 +03:00
template < typename U > static CBaseForGSApply * getApplier ( const U * t = nullptr )
2010-09-03 21:42:54 +03:00
{
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 ) ;
}
} ;
2013-06-26 14:18:27 +03:00
static CApplier < CBaseForGSApply > * applierGs = nullptr ;
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
2013-06-26 14:18:27 +03:00
template < typename T > void registerType ( const T * t = nullptr )
2009-09-07 05:29:44 +03:00
{
apps . push_back ( new CObjectCaller < T > ) ;
}
CObjectCallersHandler ( )
{
registerTypes1 ( * this ) ;
}
~ CObjectCallersHandler ( )
{
2013-06-29 16:05:48 +03:00
for ( auto & elem : apps )
delete elem ;
2009-09-07 05:29:44 +03:00
}
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
}
2013-06-26 14:18:27 +03:00
} * objCaller = nullptr ;
2009-09-07 05:29:44 +03:00
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 ;
2013-02-13 22:35:43 +03:00
}
2009-07-09 22:15:22 +03:00
else if ( type = = SPELL_NAME )
{
2013-02-13 22:35:43 +03:00
dst = SpellID ( ser ) . toSpell ( ) - > 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 :
2013-04-09 17:31:36 +03:00
logGlobal - > errorStream ( ) < < " Failed string substitution because type is " < < type ;
2011-05-28 04:02:28 +03:00
dst = " #@# " ;
return ;
2008-12-27 03:01:59 +02:00
}
2011-05-28 04:02:28 +03:00
if ( vec - > size ( ) < = ser )
{
2013-04-09 17:31:36 +03:00
logGlobal - > errorStream ( ) < < " Failed string substitution with type " < < type < < " because index " < < ser < < " is out of bounds! " ;
2011-05-28 04:02:28 +03:00
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 ( ) ;
2013-06-29 16:05:48 +03:00
for ( auto & elem : message )
2009-07-09 22:15:22 +03:00
{ //TEXACT_STRING, TLOCAL_STRING, TNUMBER, TREPLACE_ESTRING, TREPLACE_LSTRING, TREPLACE_NUMBER
2013-06-29 16:05:48 +03:00
switch ( elem )
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 :
2013-04-09 17:31:36 +03:00
logGlobal - > errorStream ( ) < < " MetaString processing error! " ;
2009-07-09 22:15:22 +03:00
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 :
2013-04-09 17:31:36 +03:00
logGlobal - > errorStream ( ) < < " MetaString processing error! " ;
2009-09-16 19:16:57 +03:00
}
}
return lista ;
}
2010-11-22 02:34:46 +02:00
2013-02-11 02:24:57 +03:00
void MetaString : : addCreReplacement ( CreatureID id , TQuantity count ) //adds sing or plural name;
2010-11-22 02:34:46 +02:00
{
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
}
2013-03-03 20:06:03 +03:00
static CGObjectInstance * createObject ( Obj id , int subid , int3 pos , PlayerColor 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
{
2013-06-29 16:05:48 +03:00
auto 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 ;
2013-02-11 02:24:57 +03:00
nobj - > defInfo = id . toDefObjInfo ( ) [ subid ] ;
2008-07-27 20:07:37 +03:00
break ;
}
nobj - > ID = id ;
nobj - > subID = subid ;
if ( ! nobj - > defInfo )
2013-04-09 17:31:36 +03:00
logGlobal - > warnStream ( ) < < " No def declaration for " < < id < < " " < < subid ;
2008-07-27 20:07:37 +03:00
nobj - > pos = pos ;
2013-06-26 14:18:27 +03:00
//nobj->state = nullptr;//new CLuaObjectScript();
2008-07-27 20:07:37 +03:00
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 ;
2013-02-11 02:24:57 +03:00
nobj - > defInfo = id . toDefObjInfo ( ) [ subid ] ;
2008-07-27 20:07:37 +03:00
return nobj ;
}
2009-09-02 17:10:19 +03:00
2013-06-26 14:18:27 +03:00
CGHeroInstance * CGameState : : HeroesPool : : pickHeroFor ( bool native , PlayerColor player , const CTown * town , bmap < ui32 , ConstTransitivePtr < CGHeroInstance > > & available , const CHeroClass * bannedClass /*= nullptr*/ ) const
2008-11-01 00:41:22 +02:00
{
2013-06-26 14:18:27 +03:00
CGHeroInstance * ret = nullptr ;
2009-08-05 03:05:37 +03:00
2013-03-03 20:06:03 +03:00
if ( player > = PlayerColor : : PLAYER_LIMIT )
2008-11-01 00:41:22 +02:00
{
2013-04-21 15:49:26 +03:00
logGlobal - > errorStream ( ) < < " Cannot pick hero for " < < town - > faction - > index < < " . Wrong owner! " ;
2013-06-26 14:18:27 +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
std : : vector < CGHeroInstance * > pool ;
2009-08-05 03:05:37 +03:00
2008-11-01 00:41:22 +02:00
if ( native )
{
2013-06-29 16:05:48 +03:00
for ( auto & elem : available )
2008-11-01 00:41:22 +02:00
{
2013-06-29 16:05:48 +03:00
if ( pavailable . find ( elem . first ) - > second & 1 < < player . getNum ( )
& & elem . second - > type - > heroClass - > faction = = town - > faction - > index )
2008-11-01 00:41:22 +02:00
{
2013-06-29 16:05:48 +03:00
pool . push_back ( elem . second ) ; //get all available heroes
2008-11-01 00:41:22 +02:00
}
}
if ( ! pool . size ( ) )
2009-08-05 03:05:37 +03:00
{
2013-04-09 17:31:36 +03:00
logGlobal - > errorStream ( ) < < " Cannot pick native hero for " < < player < < " . Picking any... " ;
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 ;
2013-06-29 16:05:48 +03:00
for ( auto & elem : available )
2008-11-01 00:41:22 +02:00
{
2013-06-29 16:05:48 +03:00
if ( pavailable . find ( elem . first ) - > second & ( 1 < < player . getNum ( ) ) & & // hero is available
( ! bannedClass | | elem . second - > type - > heroClass ! = bannedClass ) ) // and his class is not same as other hero
2008-11-01 00:41:22 +02:00
{
2013-06-29 16:05:48 +03:00
pool . push_back ( elem . second ) ;
sum + = elem . second - > type - > heroClass - > selectionProbability [ town - > faction - > index ] ; //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
{
2013-04-09 17:31:36 +03:00
logGlobal - > errorStream ( ) < < " There are no heroes available for player " < < player < < " ! " ;
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 ;
2013-06-29 16:05:48 +03:00
for ( auto & elem : pool )
2008-11-01 00:41:22 +02:00
{
2013-06-29 16:05:48 +03:00
r - = elem - > type - > heroClass - > selectionProbability [ town - > faction - > index ] ;
2009-11-15 16:06:25 +02:00
if ( r < 0 )
{
2013-06-29 16:05:48 +03:00
ret = elem ;
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
}
2013-03-03 20:06:03 +03:00
int CGameState : : pickHero ( PlayerColor owner )
2008-06-30 03:06:41 +03:00
{
2010-10-24 14:35:14 +03:00
const PlayerSettings & ps = scenarioOps - > getIthPlayersSettings ( owner ) ;
2013-05-29 01:47:15 +03:00
if ( ! isUsedHero ( HeroTypeID ( ps . hero ) ) & & ps . hero > = 0 ) //we haven't used selected hero
return ps . hero ;
2012-09-22 20:23:28 +03:00
if ( scenarioOps - > mode = = StartInfo : : CAMPAIGN )
{
auto bonus = scenarioOps - > campState - > getBonusForCurrentMap ( ) ;
2013-05-29 01:47:15 +03:00
if ( bonus & & bonus - > type = = CScenarioTravel : : STravelBonus : : HERO & & owner = = PlayerColor ( bonus - > info1 ) )
2012-09-22 20:23:28 +03:00
{
2013-05-29 01:47:15 +03:00
//TODO what if hero chosen as bonus is placed in the prison on map
if ( bonus - > info2 ! = 0xffff & & ! isUsedHero ( HeroTypeID ( 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
}
}
}
2013-05-29 01:47:15 +03:00
//list of heroes for this faction and others
std : : vector < HeroTypeID > factionHeroes , otherHeroes ;
2010-10-31 00:53:41 +03:00
2013-05-29 01:47:15 +03:00
const size_t firstHero = ps . castle * GameConstants : : HEROES_PER_TYPE * 2 ;
const size_t lastHero = std : : min ( firstHero + GameConstants : : HEROES_PER_TYPE * 2 , VLC - > heroh - > heroes . size ( ) ) - 1 ;
const auto heroesToConsider = getUnusedAllowedHeroes ( ) ;
2013-06-29 16:05:48 +03:00
for ( auto hid : heroesToConsider )
2013-05-29 01:47:15 +03:00
{
if ( vstd : : iswithin ( hid . getNum ( ) , firstHero , lastHero ) )
factionHeroes . push_back ( hid ) ;
else
otherHeroes . push_back ( hid ) ;
}
2012-10-06 11:47:13 +03:00
// we need random order to select hero
2013-05-29 11:14:01 +03:00
auto randGen = [ ] ( size_t range )
2012-12-12 17:52:42 +03:00
{
return ran ( ) % range ;
2013-05-29 11:14:01 +03:00
} ;
boost : : random_shuffle ( factionHeroes , randGen ) ; // generator must be reference
2012-10-06 11:47:13 +03:00
2013-05-29 01:47:15 +03:00
if ( factionHeroes . size ( ) )
return factionHeroes . front ( ) . getNum ( ) ;
logGlobal - > warnStream ( ) < < " Cannot find free hero of appropriate faction for player " < < owner < < " - trying to get first available... " ;
if ( otherHeroes . size ( ) )
return otherHeroes . front ( ) . getNum ( ) ;
2012-10-06 11:47:13 +03:00
2013-05-29 01:47:15 +03:00
logGlobal - > errorStream ( ) < < " No free allowed heroes! " ;
auto notAllowedHeroesButStillBetterThanCrash = getUnusedAllowedHeroes ( true ) ;
if ( notAllowedHeroesButStillBetterThanCrash . size ( ) )
return notAllowedHeroesButStillBetterThanCrash . begin ( ) - > getNum ( ) ;
2012-10-06 11:47:13 +03:00
2013-05-29 01:47:15 +03:00
logGlobal - > errorStream ( ) < < " No free heroes at all! " ;
assert ( 0 ) ; //current code can't handle this situation
2012-10-06 11:47:13 +03:00
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
2013-02-11 02:24:57 +03:00
std : : pair < Obj , 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 :
2013-02-07 20:34:50 +03:00
return std : : make_pair ( 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 :
2013-02-07 20:34:50 +03:00
return std : : make_pair ( Obj : : ARTIFACT , VLC - > arth - > getRandomArt ( CArtifact : : ART_TREASURE ) ) ;
2012-12-24 13:18:30 +03:00
case Obj : : RANDOM_MINOR_ART :
2013-02-07 20:34:50 +03:00
return std : : make_pair ( Obj : : ARTIFACT , VLC - > arth - > getRandomArt ( CArtifact : : ART_MINOR ) ) ;
2012-12-24 13:18:30 +03:00
case Obj : : RANDOM_MAJOR_ART :
2013-02-07 20:34:50 +03:00
return std : : make_pair ( Obj : : ARTIFACT , VLC - > arth - > getRandomArt ( CArtifact : : ART_MAJOR ) ) ;
2012-12-24 13:18:30 +03:00
case Obj : : RANDOM_RELIC_ART :
2013-02-07 20:34:50 +03:00
return std : : make_pair ( Obj : : ARTIFACT , VLC - > arth - > getRandomArt ( CArtifact : : ART_RELIC ) ) ;
2012-12-24 13:18:30 +03:00
case Obj : : RANDOM_HERO :
2013-02-07 20:34:50 +03:00
return std : : make_pair ( Obj : : HERO , pickHero ( obj - > tempOwner ) ) ;
2012-12-24 13:18:30 +03:00
case Obj : : RANDOM_MONSTER :
2013-06-26 14:18:27 +03:00
return std : : make_pair ( Obj : : MONSTER , VLC - > creh - > pickRandomMonster ( std : : ref ( ran ) ) ) ;
2012-12-24 13:18:30 +03:00
case Obj : : RANDOM_MONSTER_L1 :
2013-06-26 14:18:27 +03:00
return std : : make_pair ( Obj : : MONSTER , VLC - > creh - > pickRandomMonster ( std : : ref ( ran ) , 1 ) ) ;
2012-12-24 13:18:30 +03:00
case Obj : : RANDOM_MONSTER_L2 :
2013-06-26 14:18:27 +03:00
return std : : make_pair ( Obj : : MONSTER , VLC - > creh - > pickRandomMonster ( std : : ref ( ran ) , 2 ) ) ;
2012-12-24 13:18:30 +03:00
case Obj : : RANDOM_MONSTER_L3 :
2013-06-26 14:18:27 +03:00
return std : : make_pair ( Obj : : MONSTER , VLC - > creh - > pickRandomMonster ( std : : ref ( ran ) , 3 ) ) ;
2012-12-24 13:18:30 +03:00
case Obj : : RANDOM_MONSTER_L4 :
2013-06-26 14:18:27 +03:00
return std : : make_pair ( Obj : : MONSTER , VLC - > creh - > pickRandomMonster ( std : : ref ( ran ) , 4 ) ) ;
2012-12-24 13:18:30 +03:00
case Obj : : RANDOM_RESOURCE :
2013-02-07 20:34:50 +03:00
return std : : make_pair ( Obj : : RESOURCE , ran ( ) % 7 ) ; //now it's OH3 style, use %8 for mithril
2012-12-24 13:18:30 +03:00
case Obj : : RANDOM_TOWN :
2008-06-30 03:06:41 +03:00
{
2013-03-03 20:06:03 +03:00
PlayerColor align = PlayerColor ( ( static_cast < CGTownInstance * > ( obj ) ) - > alignment ) ;
2013-03-03 21:00:37 +03:00
si32 f ; // can be negative (for random)
2013-03-03 20:06:03 +03:00
if ( align > = PlayerColor : : PLAYER_LIMIT ) //same as owner / random
2008-06-30 03:06:41 +03:00
{
2013-03-03 20:06:03 +03:00
if ( obj - > tempOwner > = PlayerColor : : PLAYER_LIMIT )
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 )
{
2013-04-21 15:49:26 +03:00
do
{
f = ran ( ) % VLC - > townh - > factions . size ( ) ;
}
while ( VLC - > townh - > factions [ f ] - > town = = nullptr ) ; // find playable faction
2012-09-05 15:49:23 +03:00
}
2013-02-07 20:34:50 +03:00
return std : : make_pair ( Obj : : TOWN , f ) ;
2008-06-30 03:06:41 +03:00
}
2012-12-24 13:18:30 +03:00
case Obj : : RANDOM_MONSTER_L5 :
2013-06-26 14:18:27 +03:00
return std : : make_pair ( Obj : : MONSTER , VLC - > creh - > pickRandomMonster ( std : : ref ( ran ) , 5 ) ) ;
2012-12-24 13:18:30 +03:00
case Obj : : RANDOM_MONSTER_L6 :
2013-06-26 14:18:27 +03:00
return std : : make_pair ( Obj : : MONSTER , VLC - > creh - > pickRandomMonster ( std : : ref ( ran ) , 6 ) ) ;
2012-12-24 13:18:30 +03:00
case Obj : : RANDOM_MONSTER_L7 :
2013-06-26 14:18:27 +03:00
return std : : make_pair ( Obj : : MONSTER , VLC - > creh - > pickRandomMonster ( std : : 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
{
2013-06-29 16:05:48 +03:00
for ( auto & elem : map - > objects )
2008-06-30 03:06:41 +03:00
{
2013-06-29 16:05:48 +03:00
if ( ! elem )
2013-02-06 02:16:13 +03:00
continue ;
2013-06-29 16:05:48 +03:00
if ( elem - > ID = = Obj : : RANDOM_TOWN
& & dynamic_cast < CGTownInstance * > ( elem . get ( ) ) - > identifier = = info - > identifier )
2012-05-11 22:03:40 +03:00
{
2013-06-29 16:05:48 +03:00
randomizeObject ( elem ) ; //we have to randomize the castle first
faction = elem - > subID ;
2012-05-11 22:03:40 +03:00
break ;
}
2013-06-29 16:05:48 +03:00
else if ( elem - > ID = = Obj : : TOWN
& & dynamic_cast < CGTownInstance * > ( elem . get ( ) ) - > identifier = = info - > identifier )
2012-05-11 22:03:40 +03:00
{
2013-06-29 16:05:48 +03:00
faction = elem - > subID ;
2012-05-11 22:03:40 +03:00
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 ;
2013-02-12 22:49:40 +03:00
std : : pair < Obj , int > result ( Obj : : NO_OBJ , - 1 ) ;
2013-04-21 15:49:26 +03:00
CreatureID cid = VLC - > townh - > factions [ faction ] - > town - > 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
2013-02-12 22:49:40 +03:00
static const CreatureID factoryCreatures [ ] = { CreatureID : : STONE_GOLEM , CreatureID : : IRON_GOLEM ,
CreatureID : : GOLD_GOLEM , CreatureID : : DIAMOND_GOLEM } ;
std : : vector < CreatureID > factory ( factoryCreatures , factoryCreatures + ARRAY_COUNT ( factoryCreatures ) ) ;
2012-06-01 14:35:31 +03:00
if ( vstd : : contains ( factory , cid ) )
2013-02-07 20:34:50 +03:00
result = std : : make_pair ( Obj : : CREATURE_GENERATOR4 , 1 ) ;
2012-06-01 14:35:31 +03:00
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
2013-06-29 16:05:48 +03:00
for ( auto & iter : VLC - > objh - > cregens )
2012-05-11 22:03:40 +03:00
if ( iter . second = = cid )
2013-02-07 20:34:50 +03:00
result = std : : make_pair ( Obj : : CREATURE_GENERATOR1 , iter . first ) ;
2012-06-01 14:35:31 +03:00
2013-02-07 20:34:50 +03:00
if ( result . first = = Obj : : NO_OBJ )
2012-10-07 17:58:48 +03:00
{
2013-04-09 17:31:36 +03:00
logGlobal - > errorStream ( ) < < " Error: failed to find creature for dwelling of " < < int ( faction ) < < " of level " < < int ( level ) ;
2012-10-07 17:58:48 +03:00
auto iter = VLC - > objh - > cregens . begin ( ) ;
std : : advance ( iter , ran ( ) % VLC - > objh - > cregens . size ( ) ) ;
2013-02-07 20:34:50 +03:00
result = std : : make_pair ( Obj : : CREATURE_GENERATOR1 , iter - > first ) ;
2012-10-07 17:58:48 +03:00
}
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
}
}
2013-02-07 20:34:50 +03:00
return std : : make_pair ( Obj : : NO_OBJ , - 1 ) ;
2008-06-30 03:06:41 +03:00
}
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
{
2013-02-11 02:24:57 +03:00
std : : pair < Obj , int > ran = pickObject ( cur ) ;
if ( ran . first = = Obj : : NO_OBJ | | ran . second < 0 ) //this is not a random object, or we couldn't find anything
2008-06-30 03:06:41 +03:00
{
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 ) ;
2013-04-21 15:49:26 +03:00
t - > town = VLC - > townh - > factions [ t - > subID ] - > town ;
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 ) ;
2013-04-09 17:31:36 +03:00
if ( ! h ) { logGlobal - > warnStream ( ) < < " Wrong random hero at " < < cur - > pos ; return ; }
2008-06-30 03:06:41 +03:00
cur - > ID = ran . first ;
2013-02-13 00:32:55 +03:00
cur - > subID = ran . second ;
2008-06-30 03:06:41 +03:00
h - > type = VLC - > heroh - > heroes [ ran . second ] ;
2013-02-13 00:32:55 +03:00
h - > portrait = h - > type - > imageIndex ;
2012-12-14 18:32:53 +03:00
h - > randomizeArmy ( h - > type - > heroClass - > faction ) ;
2013-05-19 01:30:48 +03:00
map - > heroesOnMap . push_back ( h ) ;
2008-06-30 03:06:41 +03:00
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 ) ;
2013-04-09 17:31:36 +03:00
if ( ! t ) { logGlobal - > warnStream ( ) < < " Wrong random town at " < < cur - > pos ; 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
2013-04-21 15:49:26 +03:00
t - > town = VLC - > townh - > factions [ t - > subID ] - > town ;
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
2013-02-11 02:24:57 +03:00
map - > customDefs . push_back ( cur - > defInfo = ran . first . toDefObjInfo ( ) [ ran . second ] ) ;
2008-08-06 01:11:32 +03:00
if ( ! cur - > defInfo )
{
2013-04-09 17:31:36 +03:00
logGlobal - > errorStream ( ) < < " *BIG* WARNING: Missing def declaration for " < < cur - > ID < < " " < < cur - > subID ;
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 ;
2013-04-21 19:38:31 +03:00
2013-06-29 16:05:48 +03:00
for ( auto ptr : hpool . heroesPool ) // clean hero pool
2013-04-21 19:38:31 +03:00
ptr . second . dellNull ( ) ;
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 ) ;
2013-02-13 01:24:48 +03:00
ETerrainType 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
2013-02-13 01:24:48 +03:00
BFieldType terType = battleGetBattlefieldType ( tile ) ;
2010-12-25 21:23:30 +02:00
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 :
2013-02-11 02:24:57 +03:00
hero - > spells . insert ( SpellID ( 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
{
2013-02-16 17:03:47 +03:00
if ( hero - > slotEmpty ( SlotID ( i ) ) )
2010-08-01 17:40:34 +03:00
{
2013-02-16 17:03:47 +03:00
hero - > addToSlot ( SlotID ( i ) , CreatureID ( 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 :
2013-02-19 01:37:22 +03:00
gs - > giveHeroArtifact ( hero , static_cast < ArtifactID > ( curBonus - > info2 ) ) ;
2012-09-22 18:16:45 +03:00
break ;
case CScenarioTravel : : STravelBonus : : SPELL_SCROLL :
{
2013-02-13 22:35:43 +03:00
CArtifactInstance * scroll = CArtifactInstance : : createScroll ( SpellID ( curBonus - > info2 ) . toSpell ( ) ) ;
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
}
2013-06-29 16:05:48 +03:00
auto bb = new Bonus ( Bonus : : PERMANENT , Bonus : : PRIMARY_SKILL , Bonus : : CAMPAIGN_BONUS , val , scenarioOps - > campState - > currentMap , g ) ;
2012-09-22 18:16:45 +03:00
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 :
2013-02-12 22:49:40 +03:00
hero - > setSecSkillLevel ( 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
2013-04-09 17:31:36 +03:00
logGlobal - > infoStream ( ) < < " \t Using random seed: " < < si - > seedToBeUsed ;
2012-04-14 05:20:22 +03:00
ran . seed ( ( boost : : int32_t ) si - > seedToBeUsed ) ;
2010-10-27 14:36:14 +03:00
scenarioOps = new StartInfo ( * si ) ;
initialOpts = new StartInfo ( * si ) ;
2013-06-26 14:18:27 +03:00
si = nullptr ;
2010-10-27 14:36:14 +03:00
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
{
2013-05-21 22:08:06 +03:00
if ( scenarioOps - > createRandomMap ( ) )
2012-11-20 20:53:45 +03:00
{
2013-04-09 17:31:36 +03:00
logGlobal - > infoStream ( ) < < " Create random map. " ;
2013-04-29 18:51:39 +03:00
CStopWatch sw ;
2013-01-06 22:30:12 +03:00
// Gen map
2013-08-19 21:20:11 +03:00
CMapGenerator mapGenerator ;
map = mapGenerator . generate ( scenarioOps - > mapGenOptions . get ( ) , scenarioOps - > seedToBeUsed ) . release ( ) ;
2013-01-06 22:30:12 +03:00
// 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-04-14 21:52:05 +03:00
const auto & playerInfo = map - > players [ i ] ;
if ( playerInfo . canAnyonePlay ( ) )
2013-01-06 22:30:12 +03:00
{
2013-04-14 21:52:05 +03:00
PlayerSettings & playerSettings = scenarioOps - > playerInfos [ PlayerColor ( i ) ] ;
playerSettings . compOnly = ! playerInfo . canHumanPlay ;
playerSettings . team = playerInfo . team ;
playerSettings . castle = playerInfo . defaultCastle ( ) ;
if ( playerSettings . playerID = = PlayerSettings : : PLAYER_AI & & playerSettings . name . empty ( ) )
2013-01-20 17:43:58 +03:00
{
2013-04-14 21:52:05 +03:00
playerSettings . name = VLC - > generaltexth - > allTexts [ 468 ] ;
2013-01-20 17:43:58 +03:00
}
2013-04-14 21:52:05 +03:00
playerSettings . color = PlayerColor ( i ) ;
2013-01-06 22:30:12 +03:00
}
else
{
2013-03-03 20:06:03 +03:00
scenarioOps - > playerInfos . erase ( PlayerColor ( i ) ) ;
2013-01-06 22:30:12 +03:00
}
}
2013-01-20 17:43:58 +03:00
2013-04-29 18:51:39 +03:00
logGlobal - > infoStream ( ) < < boost : : format ( " Generated random map in %i ms. " ) % sw . getDiff ( ) ;
2012-11-20 20:53:45 +03:00
}
else
{
2013-04-09 17:31:36 +03:00
logGlobal - > infoStream ( ) < < " Open map file: " < < scenarioOps - > mapname ;
2012-11-20 20:53:45 +03:00
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
{
2013-04-09 17:31:36 +03:00
logGlobal - > infoStream ( ) < < " Open campaign map file: " < < scenarioOps - > campState - > currentMap ;
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 :
2013-04-09 17:31:36 +03:00
logGlobal - > errorStream ( ) < < " Wrong mode: " < < ( int ) scenarioOps - > mode ;
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 ) ;
2013-04-09 17:31:36 +03:00
logGlobal - > infoStream ( ) < < " Map loaded! " ;
2010-05-08 21:56:38 +03:00
2013-04-09 17:31:36 +03:00
logGlobal - > infoStream ( ) < < " \t Our checksum for the map: " < < map - > checksum ;
2012-04-14 05:20:22 +03:00
if ( scenarioOps - > mapfileChecksum )
2010-05-08 21:56:38 +03:00
{
2013-04-09 17:31:36 +03:00
logGlobal - > infoStream ( ) < < " \t Server checksum for " < < scenarioOps - > mapname < < " : " < < scenarioOps - > mapfileChecksum ;
2012-04-14 05:20:22 +03:00
if ( map - > checksum ! = scenarioOps - > mapfileChecksum )
2010-05-08 21:56:38 +03:00
{
2013-04-09 17:31:36 +03:00
logGlobal - > errorStream ( ) < < " Wrong map checksum!!! " ;
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
2013-04-09 17:31:36 +03:00
logGlobal - > debugStream ( ) < < " Initialization: " ;
logGlobal - > debugStream ( ) < < " \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 ;
2013-04-28 18:06:14 +03:00
static const int BORDER_WIDTH = 9 ; // grail must be at least 9 tiles away from border
2012-02-16 20:10:58 +03:00
2010-02-10 04:56:00 +02:00
// add all not blocked tiles in range
2013-04-28 18:06:14 +03:00
for ( int i = BORDER_WIDTH ; i < map - > width - BORDER_WIDTH ; i + + )
2012-11-13 14:52:23 +03:00
{
2013-04-28 18:06:14 +03:00
for ( int j = BORDER_WIDTH ; j < map - > height - BORDER_WIDTH ; j + + )
2012-11-13 14:52:23 +03:00
{
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
{
2013-04-19 14:43:11 +03:00
const TerrainTile & t = map - > getTile ( int3 ( i , j , k ) ) ;
2012-11-13 14:52:23 +03:00
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
2013-06-29 16:05:48 +03:00
for ( auto & elem : map - > objects )
if ( elem & & elem - > ID = = Obj : : HOLE )
allowedPos - = elem - > pos ;
2010-02-10 04:56:00 +02:00
if ( allowedPos . size ( ) )
map - > grailPos = allowedPos [ ran ( ) % allowedPos . size ( ) ] ;
else
2013-04-09 17:31:36 +03:00
logGlobal - > warnStream ( ) < < " Warning: Grail cannot be placed, no appropriate tile found! " ;
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
2013-04-09 17:31:36 +03:00
logGlobal - > debugStream ( ) < < " \t Picking random factions for players " ;
2013-06-29 16:05:48 +03:00
for ( auto & elem : scenarioOps - > playerInfos )
2008-06-30 03:06:41 +03:00
{
2013-06-29 16:05:48 +03:00
if ( elem . second . castle = = - 1 )
2008-06-30 03:06:41 +03:00
{
2013-06-29 16:05:48 +03:00
int randomID = ran ( ) % map - > players [ elem . first . getNum ( ) ] . allowedFactions . size ( ) ;
auto iter = map - > players [ elem . first . getNum ( ) ] . allowedFactions . begin ( ) ;
2012-09-23 17:32:49 +03:00
std : : advance ( iter , randomID ) ;
2013-06-29 16:05:48 +03:00
elem . 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
2013-04-09 17:31:36 +03:00
logGlobal - > debugStream ( ) < < " \t Randomizing objects " ;
2013-06-29 16:05:48 +03:00
for ( CGObjectInstance * obj : map - > objects )
2008-06-30 03:06:41 +03:00
{
2013-02-06 02:16:13 +03:00
if ( ! obj )
continue ;
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
}
2010-08-02 17:29:30 +03:00
/*********creating players entries in gs****************************************/
2013-04-09 17:31:36 +03:00
logGlobal - > debugStream ( ) < < " \t Creating player entries in gs " ;
2013-06-29 16:05:48 +03:00
for ( auto & elem : scenarioOps - > playerInfos )
2010-08-02 17:29:30 +03:00
{
2013-06-29 16:05:48 +03:00
std : : pair < PlayerColor , PlayerState > ins ( elem . first , PlayerState ( ) ) ;
2010-08-02 17:29:30 +03:00
ins . second . color = ins . first ;
2013-06-29 16:05:48 +03:00
ins . second . human = elem . second . playerID ;
2013-03-03 20:06:03 +03:00
ins . second . team = map - > players [ ins . first . getNum ( ) ] . 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 ) ;
}
2013-05-29 01:47:15 +03:00
/*************************replace hero placeholders*****************************/
if ( scenarioOps - > campState )
{
logGlobal - > debugStream ( ) < < " \t Replacing hero placeholders " ;
std : : vector < std : : pair < CGHeroInstance * , ObjectInstanceID > > campHeroReplacements = campaignHeroesToReplace ( ) ;
//Replace placeholders with heroes from previous missions
logGlobal - > debugStream ( ) < < " \t Setting up heroes " ;
placeCampaignHeroes ( campHeroReplacements ) ;
}
2008-08-27 13:19:18 +03:00
/*********give starting hero****************************************/
2013-04-09 17:31:36 +03:00
logGlobal - > debugStream ( ) < < " \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
{
2013-05-29 01:47:15 +03:00
if ( auto bonus = scenarioOps - > campState - > getBonusForCurrentMap ( ) )
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 )
{
2013-03-03 20:06:03 +03:00
const PlayerInfo & p = map - > players [ it - > first . getNum ( ) ] ;
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 ) ) ;
2013-02-14 02:55:42 +03:00
nnn - > id = ObjectInstanceID ( map - > objects . size ( ) ) ;
2012-09-25 17:40:39 +03:00
nnn - > initHero ( ) ;
2013-05-19 01:30:48 +03:00
map - > heroesOnMap . push_back ( nnn ) ;
2012-09-25 17:40:39 +03:00
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
2008-06-30 03:06:41 +03:00
/******************RESOURCES****************************************************/
2013-04-09 17:31:36 +03:00
logGlobal - > debugStream ( ) < < " \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
2013-06-29 16:05:48 +03:00
for ( auto & elem : players )
2008-06-30 03:06:41 +03:00
{
2013-06-29 16:05:48 +03:00
PlayerState & p = elem . second ;
2011-07-05 09:14:07 +03:00
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 ( ) ;
2013-05-29 01:47:15 +03:00
if ( chosenBonus & & 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
2013-06-29 16:05:48 +03:00
for ( 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
2013-06-29 16:05:48 +03:00
for ( auto & re : res )
2010-07-31 16:55:05 +03:00
{
2013-06-29 16:05:48 +03:00
players [ ps - > color ] . resources [ re ] + = 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
2013-05-29 01:47:15 +03:00
/*************************HEROES INIT / POOL************************************************/
2013-06-29 16:05:48 +03:00
for ( auto hero : map - > heroesOnMap ) //heroes instances initialization
2008-06-30 03:06:41 +03:00
{
2013-05-19 01:30:48 +03:00
if ( hero - > getOwner ( ) = = PlayerColor : : UNFLAGGABLE )
2008-06-30 03:06:41 +03:00
{
2013-04-09 17:31:36 +03:00
logGlobal - > warnStream ( ) < < " Warning - hero with uninitialized owner! " ;
2008-10-26 22:58:34 +02:00
continue ;
2008-06-30 03:06:41 +03:00
}
2013-02-06 13:16:44 +03:00
2013-05-19 01:30:48 +03:00
hero - > initHero ( ) ;
getPlayer ( hero - > getOwner ( ) ) - > heroes . push_back ( hero ) ;
map - > allHeroes [ hero - > type - > ID . getNum ( ) ] = hero ;
}
2010-07-08 08:52:11 +03:00
2013-06-29 16:05:48 +03:00
for ( auto obj : map - > objects ) //prisons
2010-02-10 23:31:54 +02:00
{
2013-02-06 13:16:44 +03:00
if ( obj & & obj - > ID = = Obj : : PRISON )
2013-05-19 01:30:48 +03:00
map - > allHeroes [ obj - > subID ] = dynamic_cast < CGHeroInstance * > ( obj . get ( ) ) ;
2010-02-10 23:31:54 +02:00
}
2010-07-08 08:52:11 +03:00
2013-05-29 01:47:15 +03:00
std : : set < HeroTypeID > heroesToCreate = getUnusedAllowedHeroes ( ) ; //ids of heroes to be created and put into the pool
2013-06-29 16:05:48 +03:00
for ( auto ph : map - > predefinedHeroes )
2008-10-26 22:58:34 +02:00
{
2013-05-19 01:30:48 +03:00
if ( ! vstd : : contains ( heroesToCreate , HeroTypeID ( ph - > subID ) ) )
2008-10-26 22:58:34 +02:00
continue ;
2013-02-06 13:16:44 +03:00
ph - > initHero ( ) ;
hpool . heroesPool [ ph - > subID ] = ph ;
hpool . pavailable [ ph - > subID ] = 0xff ;
2013-05-19 01:30:48 +03:00
heroesToCreate . erase ( ph - > type - > ID ) ;
map - > allHeroes [ ph - > subID ] = ph ;
2008-10-26 22:58:34 +02:00
}
2010-07-08 08:52:11 +03:00
2013-06-29 16:05:48 +03:00
for ( HeroTypeID htype : heroesToCreate ) //all not used allowed heroes go with default state into the pool
2008-10-26 22:58:34 +02:00
{
2013-06-29 16:05:48 +03:00
auto vhi = new CGHeroInstance ( ) ;
2013-05-19 01:30:48 +03:00
vhi - > initHero ( htype ) ;
int typeID = htype . getNum ( ) ;
map - > allHeroes [ typeID ] = vhi ;
hpool . heroesPool [ typeID ] = vhi ;
hpool . pavailable [ typeID ] = 0xff ;
2008-10-26 22:58:34 +02:00
}
2010-07-08 08:52:11 +03:00
2013-06-29 16:05:48 +03:00
for ( auto & elem : map - > disposedHeroes )
2008-10-26 22:58:34 +02:00
{
2013-06-29 16:05:48 +03:00
hpool . pavailable [ elem . heroId ] = elem . 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 ( ) ;
2013-05-29 01:47:15 +03:00
if ( chosenBonus & & chosenBonus - > isBonusForHero ( ) & & chosenBonus - > info1 ! = 0xFFFE ) //exclude generated heroes
2010-08-01 15:52:42 +03:00
{
//find human player
2013-03-03 20:06:03 +03:00
PlayerColor humanPlayer = PlayerColor : : NEUTRAL ;
2013-06-29 16:05:48 +03:00
for ( auto & elem : players )
2010-08-01 15:52:42 +03:00
{
2013-06-29 16:05:48 +03:00
if ( elem . second . human )
2010-08-01 15:52:42 +03:00
{
2013-06-29 16:05:48 +03:00
humanPlayer = elem . first ;
2010-08-01 15:52:42 +03:00
break ;
}
}
2013-03-03 20:06:03 +03:00
assert ( humanPlayer ! = PlayerColor : : NEUTRAL ) ;
2012-07-06 23:19:54 +03:00
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 )
2013-04-09 17:31:36 +03:00
logGlobal - > warnStream ( ) < < " Warning - cannot give bonus to hero cause there are no heroes! " ;
2010-10-30 21:54:59 +03:00
else
2012-09-22 18:16:45 +03:00
giveCampaignBonusToHero ( heroes [ maxB ] ) ;
2010-08-01 15:52:42 +03:00
}
else //specific hero
{
2013-06-29 16:05:48 +03:00
for ( auto & heroe : heroes )
2010-08-01 15:52:42 +03:00
{
2013-06-29 16:05:48 +03:00
if ( heroe - > subID = = chosenBonus - > info1 )
2010-08-01 15:52:42 +03:00
{
2013-06-29 16:05:48 +03:00
giveCampaignBonusToHero ( heroe ) ;
2010-08-01 15:52:42 +03:00
break ;
}
}
}
}
}
2010-08-03 15:34:06 +03:00
/*************************FOG**OF**WAR******************************************/
2013-04-09 17:31:36 +03:00
logGlobal - > debugStream ( ) < < " \t Fog of war " ; //FIXME: should be initialized after all bonuses are set
2013-06-29 16:05:48 +03:00
for ( auto & elem : teams )
2008-06-30 03:06:41 +03:00
{
2013-06-29 16:05:48 +03:00
elem . second . fogOfWarMap . resize ( map - > width ) ;
2008-06-30 03:06:41 +03:00
for ( int g = 0 ; g < map - > width ; + + g )
2013-06-29 16:05:48 +03:00
elem . second . fogOfWarMap [ g ] . resize ( map - > height ) ;
2008-06-30 03:06:41 +03:00
for ( int g = - 0 ; g < map - > width ; + + g )
for ( int h = 0 ; h < map - > height ; + + h )
2013-06-29 16:05:48 +03:00
elem . 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 )
2013-06-29 16:05:48 +03:00
elem . second . fogOfWarMap [ g ] [ h ] [ v ] = 0 ;
2009-03-12 01:25:59 +02:00
2013-06-29 16:05:48 +03:00
for ( CGObjectInstance * obj : map - > objects )
2008-06-30 03:06:41 +03:00
{
2013-06-29 16:05:48 +03:00
if ( ! obj | | ! vstd : : contains ( elem . second . players , obj - > tempOwner ) ) continue ; //not a flagged object
2009-03-12 01:25:59 +02:00
2013-06-29 16:05:48 +03:00
std : : unordered_set < int3 , ShashInt3 > tiles ;
2009-11-11 19:45:03 +02:00
obj - > getSightTiles ( tiles ) ;
2013-06-29 16:05:48 +03:00
for ( int3 tile : tiles )
2009-11-11 19:45:03 +02:00
{
2013-06-29 16:05:48 +03:00
elem . second . fogOfWarMap [ tile . x ] [ tile . y ] [ tile . z ] = 1 ;
2009-11-11 19:45:03 +02:00
}
2008-06-30 03:06:41 +03:00
}
2010-08-03 15:34:06 +03:00
}
2012-02-16 20:10:58 +03:00
2013-04-09 17:31:36 +03:00
logGlobal - > debugStream ( ) < < " \t Starting bonuses " ;
2013-06-29 16:05:48 +03:00
for ( auto & elem : players )
2010-08-03 15:34:06 +03:00
{
2008-08-26 00:14:00 +03:00
//starting bonus
2013-06-29 16:05:48 +03:00
if ( scenarioOps - > playerInfos [ elem . first ] . bonus = = PlayerSettings : : RANDOM )
scenarioOps - > playerInfos [ elem . first ] . bonus = static_cast < PlayerSettings : : Ebonus > ( ran ( ) % 3 ) ;
switch ( scenarioOps - > playerInfos [ elem . first ] . bonus )
2008-08-26 00:14:00 +03:00
{
2012-12-02 15:21:44 +03:00
case PlayerSettings : : GOLD :
2013-06-29 16:05:48 +03:00
elem . 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
{
2013-06-29 16:05:48 +03:00
int res = VLC - > townh - > factions [ scenarioOps - > playerInfos [ elem . first ] . castle ] - > town - > primaryRes ;
2013-04-21 15:49:26 +03:00
if ( res = = Res : : WOOD_AND_ORE )
2008-08-26 00:14:00 +03:00
{
2013-06-29 16:05:48 +03:00
elem . second . resources [ Res : : WOOD ] + = 5 + ran ( ) % 6 ;
elem . second . resources [ Res : : ORE ] + = 5 + ran ( ) % 6 ;
2008-08-26 00:14:00 +03:00
}
else
{
2013-06-29 16:05:48 +03:00
elem . second . resources [ res ] + = 3 + ran ( ) % 4 ;
2008-08-26 00:14:00 +03:00
}
break ;
}
2012-12-02 15:21:44 +03:00
case PlayerSettings : : ARTIFACT :
2008-08-26 00:14:00 +03:00
{
2013-06-29 16:05:48 +03:00
if ( ! elem . second . heroes . size ( ) )
2010-07-06 08:09:06 +03:00
{
2013-04-09 17:31:36 +03:00
logGlobal - > debugStream ( ) < < " Cannot give starting artifact - no heroes! " ;
2010-07-06 08:09:06 +03:00
break ;
}
CArtifact * toGive ;
toGive = VLC - > arth - > artifacts [ VLC - > arth - > getRandomArt ( CArtifact : : ART_TREASURE ) ] ;
2013-06-29 16:05:48 +03:00
CGHeroInstance * hero = elem . 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************************************************/
2013-04-09 17:31:36 +03:00
logGlobal - > debugStream ( ) < < " \t Towns " ;
2013-02-11 22:11:34 +03:00
//campaign bonuses for towns
if ( scenarioOps - > mode = = StartInfo : : CAMPAIGN )
{
auto chosenBonus = scenarioOps - > campState - > getBonusForCurrentMap ( ) ;
2013-05-29 01:47:15 +03:00
if ( chosenBonus & & chosenBonus - > type = = CScenarioTravel : : STravelBonus : : BUILDING )
2013-02-11 22:11:34 +03:00
{
for ( int g = 0 ; g < map - > towns . size ( ) ; + + g )
{
PlayerState * owner = getPlayer ( map - > towns [ g ] - > getOwner ( ) ) ;
if ( owner )
{
2013-03-03 20:06:03 +03:00
PlayerInfo & pi = map - > players [ owner - > color . getNum ( ) ] ;
2013-02-11 22:11:34 +03:00
if ( owner - > human & & //human-owned
map - > towns [ g ] - > pos = = pi . posOfMainTown + int3 ( 2 , 0 , 0 ) )
{
map - > towns [ g ] - > builtBuildings . insert (
2013-04-21 15:49:26 +03:00
CBuildingHandler : : campToERMU ( chosenBonus - > info1 , map - > towns [ g ] - > subID , map - > towns [ g ] - > builtBuildings ) ) ;
2013-02-11 22:11:34 +03:00
break ;
}
}
}
}
}
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
2013-06-29 16:05:48 +03:00
for ( auto & elem : map - > towns )
2008-06-30 03:06:41 +03:00
{
2013-06-29 16:05:48 +03:00
CGTownInstance * vti = ( elem ) ;
2008-06-30 03:06:41 +03:00
if ( ! vti - > town )
2013-04-21 15:49:26 +03:00
vti - > town = VLC - > townh - > factions [ vti - > subID ] - > town ;
2008-06-30 03:06:41 +03:00
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
2013-02-11 22:11:34 +03:00
if ( vstd : : contains ( vti - > builtBuildings , BuildingID : : DEFAULT ) ) //give standard set of buildings
2008-06-30 03:06:41 +03:00
{
2013-02-11 22:11:34 +03:00
vti - > builtBuildings . erase ( BuildingID : : DEFAULT ) ;
2013-02-11 02:24:57 +03:00
vti - > builtBuildings . insert ( BuildingID : : VILLAGE_HALL ) ;
vti - > builtBuildings . insert ( BuildingID : : TAVERN ) ;
vti - > builtBuildings . insert ( BuildingID : : DWELL_FIRST ) ;
2008-06-30 03:06:41 +03:00
if ( ran ( ) % 2 )
2013-02-11 22:11:34 +03:00
vti - > builtBuildings . insert ( BuildingID : : DWELL_LVL_2 ) ;
2010-06-30 22:27:35 +03:00
}
2012-02-16 20:10:58 +03:00
2013-09-29 23:53:45 +03:00
//#1444 - remove entries that don't have buildings defined (like some unused extra town hall buildings)
vstd : : erase_if ( vti - > builtBuildings , [ vti ] ( BuildingID bid ) {
return ! vti - > town - > buildings . count ( bid ) | | ! vti - > town - > buildings . at ( bid ) ; } ) ;
2013-07-21 13:08:32 +03:00
if ( vstd : : contains ( vti - > builtBuildings , BuildingID : : SHIPYARD ) & & vti - > shipyardStatus ( ) = = IBoatGenerator : : TILE_BLOCKED )
2013-02-11 02:24:57 +03:00
vti - > builtBuildings . erase ( BuildingID : : 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
{
2013-02-11 22:11:34 +03:00
vti - > builtBuildings . erase ( BuildingID ( - 31 - i ) ) ; //remove old ID
2010-02-13 17:56:34 +02:00
if ( vti - > town - > hordeLvl [ 0 ] = = i ) //if town first horde is this one
{
2013-02-11 02:24:57 +03:00
vti - > builtBuildings . insert ( BuildingID : : HORDE_1 ) ; //add it
if ( vstd : : contains ( vti - > builtBuildings , ( BuildingID : : DWELL_UP_FIRST + i ) ) ) //if we have upgraded dwelling as well
vti - > builtBuildings . insert ( BuildingID : : 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
{
2013-02-11 02:24:57 +03:00
vti - > builtBuildings . insert ( BuildingID : : HORDE_2 ) ;
if ( vstd : : contains ( vti - > builtBuildings , ( BuildingID : : DWELL_UP_FIRST + i ) ) )
vti - > builtBuildings . insert ( BuildingID : : HORDE_2_UPGR ) ;
2010-02-13 17:56:34 +02:00
}
}
2012-02-16 20:10:58 +03:00
2013-09-27 18:20:42 +03:00
//Early check for #1444-like problems
for ( auto building : vti - > builtBuildings )
assert ( vti - > town - > buildings [ building ] ) ;
2011-08-25 23:02:38 +03:00
//town events
2013-06-29 16:05:48 +03:00
for ( CCastleEvent & ev : vti - > events )
2011-08-25 23:02:38 +03:00
{
2011-12-14 00:23:17 +03:00
for ( int i = 0 ; i < GameConstants : : CREATURES_PER_TOWN ; i + + )
2013-02-19 01:37:22 +03:00
if ( vstd : : contains ( ev . buildings , ( - 31 - i ) ) ) //if we have horde for this level
2010-08-25 17:57:58 +03:00
{
2013-02-19 01:37:22 +03:00
ev . buildings . erase ( BuildingID ( - 31 - i ) ) ;
2010-08-25 17:57:58 +03:00
if ( vti - > town - > hordeLvl [ 0 ] = = i )
2013-02-19 01:37:22 +03:00
ev . buildings . insert ( BuildingID : : HORDE_1 ) ;
2010-08-25 17:57:58 +03:00
if ( vti - > town - > hordeLvl [ 1 ] = = i )
2013-02-19 01:37:22 +03:00
ev . buildings . insert ( BuildingID : : 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 ) ;
2013-02-13 22:35:43 +03:00
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
{
2013-02-13 22:35:43 +03:00
CSpell * s = vti - > obligatorySpells [ z ] . toSpell ( ) ;
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 + + )
2013-02-13 22:35:43 +03:00
total + = vti - > possibleSpells [ ps ] . toSpell ( ) - > 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
{
2013-02-13 22:35:43 +03:00
r - = vti - > possibleSpells [ ps ] . toSpell ( ) - > probabilities [ vti - > subID ] ;
2008-08-20 09:57:53 +03:00
if ( r < 0 )
{
sel = ps ;
break ;
}
}
if ( sel < 0 )
sel = 0 ;
2013-02-13 22:35:43 +03:00
CSpell * s = vti - > possibleSpells [ sel ] . toSpell ( ) ;
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 ( ) ;
2013-03-03 20:06:03 +03:00
if ( vti - > getOwner ( ) ! = PlayerColor : : NEUTRAL )
2009-03-09 12:37:49 +02:00
getPlayer ( vti - > getOwner ( ) ) - > towns . push_back ( vti ) ;
2008-06-30 03:06:41 +03:00
}
2013-04-09 17:31:36 +03:00
logGlobal - > debugStream ( ) < < " \t Object initialization " ;
2011-02-04 16:58:14 +02:00
objCaller - > preInit ( ) ;
2013-06-29 16:05:48 +03:00
for ( CGObjectInstance * obj : map - > objects )
2011-02-04 16:58:14 +02:00
{
2013-02-06 02:16:13 +03:00
if ( obj )
obj - > initObj ( ) ;
2011-02-04 16:58:14 +02:00
}
2013-06-29 16:05:48 +03:00
for ( CGObjectInstance * obj : map - > objects )
2012-07-19 12:10:55 +03:00
{
2013-02-06 02:16:13 +03:00
if ( ! obj )
continue ;
2012-07-19 12:10:55 +03:00
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
{
2013-03-03 20:06:03 +03:00
if ( k - > first = = PlayerColor : : NEUTRAL )
2008-06-30 03:06:41 +03:00
continue ;
2008-08-20 09:57:53 +03:00
//init visiting and garrisoned heroes
2013-06-29 16:05:48 +03:00
for ( CGHeroInstance * h : k - > second . heroes )
2012-02-16 20:10:58 +03:00
{
2013-06-29 16:05:48 +03:00
for ( 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
2013-04-09 17:31:36 +03:00
logGlobal - > debugStream ( ) < < " \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 ( ) ;
2013-04-09 17:31:36 +03:00
logGlobal - > infoStream ( ) < < " Seed after init is " < < seedAfterInit < < " (before was " < < scenarioOps - > seedToBeUsed < < " ) " ;
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 " ) )
{
2013-04-09 17:31:36 +03:00
logGlobal - > infoStream ( ) < < " Loading duel settings from JSON file: " < < scenarioOps - > mapname ;
2012-07-26 03:48:44 +03:00
dp = DuelParameters : : fromJSON ( scenarioOps - > mapname ) ;
2013-04-09 17:31:36 +03:00
logGlobal - > infoStream ( ) < < " JSON file has been successfully read! " ;
2012-07-26 03:48:44 +03:00
}
else
{
CLoadFile lf ( scenarioOps - > mapname ) ;
lf > > dp ;
}
}
catch ( . . . )
{
2013-04-09 17:31:36 +03:00
logGlobal - > errorStream ( ) < < " Cannot load duel settings from " < < scenarioOps - > mapname ;
2012-07-26 03:48:44 +03:00
throw ;
}
2013-06-29 16:05:48 +03:00
const CArmedInstance * armies [ 2 ] = { nullptr } ;
const CGHeroInstance * heroes [ 2 ] = { nullptr } ;
2013-06-26 14:18:27 +03:00
CGTownInstance * town = nullptr ;
2012-07-26 03:48:44 +03:00
for ( int i = 0 ; i < 2 ; i + + )
{
2013-06-26 14:18:27 +03:00
CArmedInstance * obj = nullptr ;
2012-07-26 03:48:44 +03:00
if ( dp . sides [ i ] . heroId > = 0 )
{
const DuelParameters : : SideSettings & ss = dp . sides [ i ] ;
2013-06-29 16:05:48 +03:00
auto h = new CGHeroInstance ( ) ;
2012-07-26 03:48:44 +03:00
armies [ i ] = heroes [ i ] = h ;
obj = h ;
h - > subID = ss . heroId ;
for ( int i = 0 ; i < ss . heroPrimSkills . size ( ) ; i + + )
2013-02-04 22:43:16 +03:00
h - > pushPrimSkill ( static_cast < PrimarySkill : : PrimarySkill > ( i ) , ss . heroPrimSkills [ i ] ) ;
2012-07-26 03:48:44 +03:00
2013-11-03 15:51:25 +03:00
if ( ! ss . spells . empty ( ) )
2012-07-26 03:48:44 +03:00
{
h - > putArtifact ( ArtifactPosition : : SPELLBOOK , CArtifactInstance : : createNewArtifactInstance ( 0 ) ) ;
boost : : copy ( ss . spells , std : : inserter ( h - > spells , h - > spells . begin ( ) ) ) ;
}
2013-06-29 16:05:48 +03:00
for ( auto & parka : ss . artifacts )
2012-07-26 03:48:44 +03:00
{
2013-02-12 22:49:40 +03:00
h - > putArtifact ( ArtifactPosition ( parka . first ) , parka . second ) ;
2012-07-26 03:48:44 +03:00
}
typedef const std : : pair < si32 , si8 > & TSecSKill ;
2013-06-29 16:05:48 +03:00
for ( TSecSKill secSkill : ss . heroSecSkills )
2013-02-12 22:49:40 +03:00
h - > setSecSkillLevel ( SecondarySkill ( secSkill . first ) , secSkill . second , 1 ) ;
2012-07-26 03:48:44 +03:00
2013-05-19 01:30:48 +03:00
h - > initHero ( HeroTypeID ( h - > subID ) ) ;
2012-07-26 03:48:44 +03:00
obj - > initObj ( ) ;
}
else
{
2013-06-29 16:05:48 +03:00
auto c = new CGCreature ( ) ;
2012-07-26 03:48:44 +03:00
armies [ i ] = obj = c ;
//c->subID = 34;
}
2013-03-03 20:06:03 +03:00
obj - > setOwner ( PlayerColor ( i ) ) ;
2012-07-26 03:48:44 +03:00
for ( int j = 0 ; j < ARRAY_COUNT ( dp . sides [ i ] . stacks ) ; j + + )
{
2013-02-11 02:24:57 +03:00
CreatureID cre = dp . sides [ i ] . stacks [ j ] . type ;
2012-07-26 03:48:44 +03:00
TQuantity count = dp . sides [ i ] . stacks [ j ] . count ;
2013-02-16 17:03:47 +03:00
if ( count | | obj - > hasStackAtSlot ( SlotID ( j ) ) )
obj - > setCreature ( SlotID ( j ) , cre , count ) ;
2012-07-26 03:48:44 +03:00
}
2013-06-29 16:05:48 +03:00
for ( const DuelParameters : : CusomCreature & cc : dp . creatures )
2012-07-26 03:48:44 +03:00
{
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
}
}
2013-02-04 00:05:44 +03:00
curB = BattleInfo : : setupBattle ( int3 ( ) , dp . terType , dp . bfieldType , armies , heroes , false , town ) ;
2012-07-26 03:48:44 +03:00
curB - > obstacles = dp . obstacles ;
curB - > localInit ( ) ;
return ;
}
2013-02-13 01:24:48 +03:00
BFieldType 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 )
2013-02-04 00:05:44 +03:00
return BFieldType : : NONE ;
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 ( ) ) )
2013-02-04 00:05:44 +03:00
return BFieldType : : SUBTERRANEAN ;
2010-07-31 03:26:34 +03:00
2013-06-29 16:05:48 +03:00
for ( 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 :
2013-02-04 00:05:44 +03:00
return BFieldType : : CLOVER_FIELD ;
2012-04-23 22:56:37 +03:00
case Obj : : CURSED_GROUND1 : case Obj : : CURSED_GROUND2 :
2013-02-04 00:05:44 +03:00
return BFieldType : : CURSED_GROUND ;
2012-04-23 22:56:37 +03:00
case Obj : : EVIL_FOG :
2013-02-04 00:05:44 +03:00
return BFieldType : : EVIL_FOG ;
2012-04-23 22:56:37 +03:00
case Obj : : FAVORABLE_WINDS :
2013-02-04 00:05:44 +03:00
return BFieldType : : FAVOURABLE_WINDS ;
2012-04-23 22:56:37 +03:00
case Obj : : FIERY_FIELDS :
2013-02-04 00:05:44 +03:00
return BFieldType : : FIERY_FIELDS ;
2012-04-23 22:56:37 +03:00
case Obj : : HOLY_GROUNDS :
2013-02-04 00:05:44 +03:00
return BFieldType : : HOLY_GROUND ;
2012-04-23 22:56:37 +03:00
case Obj : : LUCID_POOLS :
2013-02-04 00:05:44 +03:00
return BFieldType : : LUCID_POOLS ;
2012-04-23 22:56:37 +03:00
case Obj : : MAGIC_CLOUDS :
2013-02-04 00:05:44 +03:00
return BFieldType : : MAGIC_CLOUDS ;
2012-04-23 22:56:37 +03:00
case Obj : : MAGIC_PLAINS1 : case Obj : : MAGIC_PLAINS2 :
2013-02-04 00:05:44 +03:00
return BFieldType : : MAGIC_PLAINS ;
2012-04-23 22:56:37 +03:00
case Obj : : ROCKLANDS :
2013-02-04 00:05:44 +03:00
return BFieldType : : ROCKLANDS ;
2009-07-01 18:58:20 +03:00
}
}
2009-02-14 15:49:30 +02:00
2012-04-08 05:29:11 +03:00
if ( ! t . isWater ( ) & & t . isCoastal ( ) )
2013-02-04 00:05:44 +03:00
return BFieldType : : SAND_SHORE ;
2012-04-08 05:29:11 +03:00
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 :
2013-02-13 01:24:48 +03:00
return BFieldType ( rand ( ) % 3 + 3 ) ;
2012-10-26 20:51:05 +03:00
case ETerrainType : : SAND :
2013-02-04 00:05:44 +03:00
return BFieldType : : SAND_MESAS ; //TODO: coast support
2012-10-26 20:51:05 +03:00
case ETerrainType : : GRASS :
2013-02-13 01:24:48 +03:00
return BFieldType ( rand ( ) % 2 + 6 ) ;
2012-10-26 20:51:05 +03:00
case ETerrainType : : SNOW :
2013-02-13 01:24:48 +03:00
return BFieldType ( rand ( ) % 2 + 10 ) ;
2012-10-26 20:51:05 +03:00
case ETerrainType : : SWAMP :
2013-02-04 00:05:44 +03:00
return BFieldType : : SWAMP_TREES ;
2012-10-26 20:51:05 +03:00
case ETerrainType : : ROUGH :
2013-02-04 00:05:44 +03:00
return BFieldType : : ROUGH ;
2012-10-26 20:51:05 +03:00
case ETerrainType : : SUBTERRANEAN :
2013-02-04 00:05:44 +03:00
return BFieldType : : SUBTERRANEAN ;
2012-10-26 20:51:05 +03:00
case ETerrainType : : LAVA :
2013-02-04 00:05:44 +03:00
return BFieldType : : LAVA ;
2012-10-26 20:51:05 +03:00
case ETerrainType : : WATER :
2013-02-04 00:05:44 +03:00
return BFieldType : : SHIP ;
2012-10-26 20:51:05 +03:00
case ETerrainType : : ROCK :
2013-02-04 00:05:44 +03:00
return BFieldType : : ROCKLANDS ;
2009-02-10 16:21:51 +02:00
default :
2013-02-04 00:05:44 +03:00
return BFieldType : : NONE ;
2009-02-10 16:21:51 +02:00
}
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 ;
2013-06-26 14:18:27 +03:00
const CGHeroInstance * h = stack . armyObj - > ID = = Obj : : HERO ? static_cast < const CGHeroInstance * > ( stack . armyObj ) : nullptr ;
const CGTownInstance * t = nullptr ;
2010-07-15 06:04:57 +03:00
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 ) ) ;
2013-06-29 16:05:48 +03:00
for ( const Bonus * it : * lista )
2010-07-17 09:49:16 +03:00
{
2013-02-11 02:24:57 +03:00
auto nid = CreatureID ( 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
{
2013-06-29 16:05:48 +03:00
for ( 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
{
2013-06-29 16:05:48 +03:00
for ( auto 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
2013-02-07 20:34:50 +03:00
if ( h & & map - > getTile ( h - > visitablePos ( ) ) . visitableObjects . front ( ) - > ID = = Obj : : HILL_FORT )
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 ) ] ;
2013-06-29 16:05:48 +03:00
for ( auto nid : base - > upgrades )
2010-07-15 06:04:57 +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 ) * 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 ;
2013-07-23 18:03:01 +03:00
for ( Res : : ResourceSet & cost : ret . cost )
cost . positive ( ) ; //upgrade cost can't be negative, ignore missing resources
2008-08-15 15:11:42 +03:00
return ret ;
}
2008-09-07 06:38:37 +03:00
2013-03-03 20:06:03 +03:00
PlayerRelations : : PlayerRelations CGameState : : getPlayerRelations ( PlayerColor color1 , PlayerColor color2 )
2010-08-13 13:46:08 +03:00
{
if ( color1 = = color2 )
2013-02-04 00:05:44 +03:00
return PlayerRelations : : SAME_PLAYER ;
2013-03-03 20:06:03 +03:00
if ( color1 = = PlayerColor : : NEUTRAL | | color2 = = PlayerColor : : NEUTRAL ) //neutral player has no friends
2013-02-04 00:05:44 +03:00
return PlayerRelations : : ENEMIES ;
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 ) )
2013-02-04 00:05:44 +03:00
return PlayerRelations : : ALLIES ;
return PlayerRelations : : ENEMIES ;
2010-08-13 13:46:08 +03:00
}
2010-07-10 05:15:49 +03:00
void CGameState : : getNeighbours ( const TerrainTile & srct , int3 tile , std : : vector < int3 > & vec , const boost : : logic : : tribool & onLand , bool limitCoastSailing )
2009-02-12 16:44:58 +02:00
{
2011-09-19 23:50:25 +03:00
static const int3 dirs [ ] = { int3 ( 0 , 1 , 0 ) , int3 ( 0 , - 1 , 0 ) , int3 ( - 1 , 0 , 0 ) , int3 ( + 1 , 0 , 0 ) ,
2009-07-19 04:00:19 +03:00
int3 ( 1 , 1 , 0 ) , int3 ( - 1 , 1 , 0 ) , int3 ( 1 , - 1 , 0 ) , int3 ( - 1 , - 1 , 0 ) } ;
2013-06-29 16:05:48 +03:00
for ( auto & dir : dirs )
2009-02-12 16:44:58 +02:00
{
2013-06-29 16:05:48 +03:00
const int3 hlp = tile + dir ;
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
2013-06-29 16:05:48 +03:00
if ( srct . terType = = ETerrainType : : WATER & & limitCoastSailing & & hlpt . terType = = ETerrainType : : WATER & & dir . x & & dir . y ) //diagonal move through water
2010-07-10 05:15:49 +03:00
{
int3 hlp1 = tile ,
hlp2 = tile ;
2013-06-29 16:05:48 +03:00
hlp1 . x + = dir . x ;
hlp2 . y + = dir . y ;
2010-07-10 05:15:49 +03:00
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 ;
2013-04-19 14:43:11 +03:00
TerrainTile & s = map - > getTile ( src ) ,
& d = map - > getTile ( dest ) ;
2009-02-12 16:44:58 +02:00
//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 ) ;
2013-06-29 16:05:48 +03:00
for ( auto & elem : vec )
2009-02-12 16:44:58 +02:00
{
2013-06-29 16:05:48 +03:00
int fcost = getMovementCost ( h , dest , elem , left , false ) ;
2009-02-12 16:44:58 +02:00
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-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 ;
2013-04-19 14:43:11 +03:00
const TerrainTile & posTile = map - > getTile ( pos ) ;
2012-11-14 17:27:18 +03:00
if ( posTile . visitable )
{
2013-06-29 16:05:48 +03:00
for ( CGObjectInstance * obj : posTile . visitableObjects )
2012-11-14 17:27:18 +03:00
{
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 ) )
{
2013-04-19 14:43:11 +03:00
const auto & tile = map - > getTile ( pos ) ;
2013-01-15 17:20:48 +03:00
if ( tile . visitable & & ( tile . isWater ( ) = = posTile . isWater ( ) ) )
2012-11-14 17:27:18 +03:00
{
2013-06-29 16:05:48 +03:00
for ( CGObjectInstance * obj : tile . visitableObjects )
2012-11-14 17:27:18 +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-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 ) ;
2013-04-19 14:43:11 +03:00
const TerrainTile & posTile = map - > getTile ( pos ) ;
2012-02-16 20:10:58 +03:00
if ( posTile . visitable )
2010-05-27 00:59:58 +03:00
{
2013-06-29 16:05:48 +03:00
for ( 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
{
2013-04-19 14:43:11 +03:00
const auto & tile = map - > getTile ( pos ) ;
2013-01-15 17:20:48 +03:00
if ( tile . visitable & & ( tile . isWater ( ) = = posTile . isWater ( ) ) )
2010-05-27 00:59:58 +03:00
{
2013-06-29 16:05:48 +03:00
for ( 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 ) ;
}
2013-03-03 20:06:03 +03:00
bool CGameState : : isVisible ( int3 pos , PlayerColor player )
2009-07-30 15:49:45 +03:00
{
2013-03-03 20:06:03 +03:00
if ( player = = PlayerColor : : NEUTRAL )
2009-07-31 14:20:53 +03:00
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
}
2013-03-03 20:06:03 +03:00
bool CGameState : : isVisible ( const CGObjectInstance * obj , boost : : optional < PlayerColor > player )
2009-07-30 15:49:45 +03:00
{
2013-02-11 17:42:09 +03:00
if ( ! player )
2011-05-03 06:14:18 +03:00
return true ;
2013-03-03 20:06:03 +03:00
if ( * player = = PlayerColor : : NEUTRAL ) //-> 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 )
2013-02-11 17:42:09 +03:00
& & isVisible ( pos , * player ) )
2010-12-25 21:23:30 +02:00
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
2013-03-03 20:06:03 +03:00
int CGameState : : victoryCheck ( PlayerColor player ) const
2010-01-29 22:52:45 +02:00
{
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
2013-06-29 16:05:48 +03:00
for ( auto & elem : p - > heroes )
if ( elem - > 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 + + )
{
2013-06-26 14:18:27 +03:00
const CArmedInstance * ai = nullptr ;
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
{
2013-06-29 16:05:48 +03:00
for ( auto & elem : ai - > Slots ( ) ) //iterate through army
if ( elem . second - > type - > idNumber = = map - > victoryCondition . objectId ) //it's searched creature
total + = elem . 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 :
2013-06-29 16:05:48 +03:00
for ( const CGTownInstance * t : map - > towns )
2010-05-14 05:18:37 +03:00
if ( ( t = = map - > victoryCondition . obj | | ! map - > victoryCondition . obj )
2012-02-16 20:10:58 +03:00
& & t - > tempOwner = = player
2013-02-11 02:24:57 +03:00
& & t - > hasBuilt ( BuildingID : : GRAIL ) )
2010-01-29 22:52:45 +02:00
return 1 ;
break ;
2011-12-14 00:23:17 +03:00
case EVictoryConditionType : : BEATHERO :
2013-03-03 20:06:03 +03:00
if ( map - > victoryCondition . obj - > tempOwner > = PlayerColor : : 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 :
2013-02-14 02:55:42 +03:00
if ( ! getObj ( map - > victoryCondition . obj - > id ) ) //target monster 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 : : TAKEDWELLINGS :
2013-06-29 16:05:48 +03:00
for ( auto & elem : map - > objects )
2010-01-29 22:52:45 +02:00
{
2013-06-29 16:05:48 +03:00
if ( elem & & elem - > tempOwner ! = player ) //check not flagged objs
2010-01-29 22:52:45 +02:00
{
2013-06-29 16:05:48 +03:00
switch ( elem - > ID )
2010-01-29 22:52:45 +02:00
{
2013-02-11 02:24:57 +03:00
case Obj : : CREATURE_GENERATOR1 : case Obj : : CREATURE_GENERATOR2 :
case Obj : : CREATURE_GENERATOR3 : case Obj : : CREATURE_GENERATOR4 :
case Obj : : RANDOM_DWELLING : case Obj : : RANDOM_DWELLING_LVL : case Obj : : RANDOM_DWELLING_FACTION :
2010-01-29 22:52:45 +02:00
return 0 ; //found not flagged dwelling - player not won
}
}
}
return 1 ;
break ;
2011-12-14 00:23:17 +03:00
case EVictoryConditionType : : TAKEMINES :
2013-06-29 16:05:48 +03:00
for ( auto & elem : map - > objects )
2010-01-29 22:52:45 +02:00
{
2013-06-29 16:05:48 +03:00
if ( elem & & elem - > tempOwner ! = player ) //check not flagged objs
2010-01-29 22:52:45 +02:00
{
2013-06-29 16:05:48 +03:00
switch ( elem - > ID )
2010-01-29 22:52:45 +02:00
{
2013-02-11 02:24:57 +03:00
case Obj : : MINE : case Obj : : ABANDONED_MINE :
2010-01-29 22:52:45 +02:00
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 ;
}
2013-03-03 20:06:03 +03:00
PlayerColor CGameState : : checkForStandardWin ( ) const
2010-01-29 22:52:45 +02:00
{
//std victory condition is:
//all enemies lost
2013-03-03 20:06:03 +03:00
PlayerColor supposedWinner = PlayerColor : : NEUTRAL ;
TeamID winnerTeam = TeamID : : NO_TEAM ;
2013-06-29 16:05:48 +03:00
for ( auto & elem : players )
2010-01-29 22:52:45 +02:00
{
2013-06-29 16:05:48 +03:00
if ( elem . second . status = = EPlayerStatus : : INGAME & & elem . first < PlayerColor : : PLAYER_LIMIT )
2010-01-29 22:52:45 +02:00
{
2013-03-03 20:06:03 +03:00
if ( supposedWinner = = PlayerColor : : NEUTRAL )
2010-01-29 22:52:45 +02:00
{
//first player remaining ingame - candidate for victory
2013-06-29 16:05:48 +03:00
supposedWinner = elem . second . color ;
winnerTeam = elem . second . team ;
2010-01-29 22:52:45 +02:00
}
2013-06-29 16:05:48 +03:00
else if ( winnerTeam ! = elem . second . team )
2010-01-29 22:52:45 +02:00
{
//current candidate has enemy remaining in game -> no vicotry
2013-03-03 20:06:03 +03:00
return PlayerColor : : NEUTRAL ;
2010-01-29 22:52:45 +02:00
}
}
}
return supposedWinner ;
}
2013-03-03 20:06:03 +03:00
bool CGameState : : checkForStandardLoss ( PlayerColor player ) const
2010-01-29 22:52:45 +02:00
{
//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
{
2013-03-03 20:06:03 +03:00
typedef std : : pair < PlayerColor , si64 > TStat ;
2010-02-11 21:18:30 +02:00
//converts [<player's color, value>] to vec[place] -> platers
2013-03-03 20:06:03 +03:00
static std : : vector < std : : vector < PlayerColor > > 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
2013-03-03 20:06:03 +03:00
std : : vector < std : : vector < PlayerColor > > ret ;
std : : vector < PlayerColor > 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
2013-03-03 20:06:03 +03:00
std : : vector < PlayerColor > 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 ;
}
2013-03-03 20:06:03 +03:00
static const CGHeroInstance * findBestHero ( CGameState * gs , PlayerColor color )
2010-02-11 21:18:30 +02:00
{
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 ( ) )
2013-06-26 14:18:27 +03:00
return nullptr ;
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 ;
2013-06-29 16:05:48 +03:00
for ( 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 ;
2013-06-29 16:05:48 +03:00
for ( auto h : ps - > heroes )
2012-11-11 00:56:19 +03:00
{
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) \
{ \
2013-03-03 20:06:03 +03:00
std : : vector < std : : pair < PlayerColor , si64 > > stats ; \
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
{ \
2013-03-03 20:06:03 +03:00
if ( g - > second . color = = PlayerColor : : NEUTRAL ) \
2010-02-01 19:51:33 +02:00
continue ; \
2013-03-03 20:06:03 +03:00
std : : pair < PlayerColor , si64 > stat ; \
2010-02-01 19:51:33 +02:00
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
}
2013-06-29 16:05:48 +03:00
for ( auto & elem : players )
2010-02-01 19:51:33 +02:00
{
2013-06-29 16:05:48 +03:00
if ( elem . second . color ! = PlayerColor : : NEUTRAL )
tgi . playerColors . push_back ( elem . second . color ) ;
2010-02-01 19:51:33 +02:00
}
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
{
2013-03-03 20:06:03 +03:00
if ( g - > second . color = = PlayerColor : : NEUTRAL )
2010-02-04 20:40:40 +02:00
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-03-02 19:55:51 +03:00
FILL_FIELD ( obelisks , CGObelisk : : visited [ gs - > getPlayerTeam ( g - > second . color ) - > id ] )
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
{
2013-03-03 20:06:03 +03:00
if ( g - > second . color = = PlayerColor : : NEUTRAL ) //do nothing for neutral player
2010-02-06 15:49:14 +02:00
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
{
2013-03-03 20:06:03 +03:00
tgi . personality [ g - > second . color ] = map - > players [ g - > second . color . getNum ( ) ] . 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
{
2013-03-03 20:06:03 +03:00
if ( g - > second . color = = PlayerColor : : NEUTRAL ) //do nothing for neutral player
2010-02-06 15:49:14 +02:00
continue ;
int bestCre = - 1 ; //best creature's ID
2013-06-29 16:05:48 +03:00
for ( auto & elem : g - > second . heroes )
2010-02-06 15:49:14 +02:00
{
2013-06-29 16:05:48 +03:00
for ( auto it = elem - > Slots ( ) . begin ( ) ; it ! = elem - > 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
}
2013-03-03 20:06:03 +03:00
int CGameState : : lossCheck ( PlayerColor player ) const
2010-01-29 22:52:45 +02:00
{
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 ( ) ;
2013-06-29 16:05:48 +03:00
for ( CGTownInstance * t : map - > towns )
2011-02-22 11:47:25 +02:00
{
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 ) ;
2013-06-29 16:05:48 +03:00
for ( PlayerColor teamMember : k - > second . players )
2011-02-04 16:58:14 +02:00
{
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 ( )
{
2013-06-29 16:05:48 +03:00
for ( CGObjectInstance * obj : map - > objects )
2011-02-04 16:58:14 +02:00
{
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
}
2013-02-19 01:37:22 +03:00
void CGameState : : giveHeroArtifact ( CGHeroInstance * h , ArtifactID aid )
2012-02-17 22:30:40 +03:00
{
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
}
2013-05-29 01:47:15 +03:00
std : : set < HeroTypeID > CGameState : : getUnusedAllowedHeroes ( bool alsoIncludeNotAllowed /*= false*/ ) const
{
std : : set < HeroTypeID > ret ;
for ( int i = 0 ; i < map - > allowedHeroes . size ( ) ; i + + )
if ( map - > allowedHeroes [ i ] | | alsoIncludeNotAllowed )
ret . insert ( HeroTypeID ( i ) ) ;
2013-06-29 16:05:48 +03:00
for ( auto hero : map - > heroesOnMap ) //heroes instances initialization
2013-05-29 01:47:15 +03:00
{
if ( hero - > type )
ret - = hero - > type - > ID ;
else
ret - = HeroTypeID ( hero - > subID ) ;
}
2013-06-29 16:05:48 +03:00
for ( auto obj : map - > objects ) //prisons
2013-05-29 01:47:15 +03:00
if ( obj & & obj - > ID = = Obj : : PRISON )
ret - = HeroTypeID ( obj - > subID ) ;
return ret ;
}
std : : vector < std : : pair < CGHeroInstance * , ObjectInstanceID > > CGameState : : campaignHeroesToReplace ( )
{
std : : vector < std : : pair < CGHeroInstance * , ObjectInstanceID > > ret ;
auto replaceHero = [ & ] ( ObjectInstanceID objId , CGHeroInstance * ghi )
{
ret . push_back ( std : : make_pair ( ghi , objId ) ) ;
// ghi->tempOwner = getHumanPlayerInfo()[0]->color;
// ghi->id = objId;
// gs->map->objects[objId] = ghi;
// gs->map->heroes.push_back(ghi);
} ;
auto campaign = scenarioOps - > campState ;
if ( auto bonus = campaign - > getBonusForCurrentMap ( ) )
{
std : : vector < CGHeroInstance * > Xheroes ;
if ( bonus - > type = = CScenarioTravel : : STravelBonus : : PLAYER_PREV_SCENARIO )
{
Xheroes = campaign - > camp - > scenarios [ bonus - > info2 ] . crossoverHeroes ;
}
//selecting heroes by type
for ( int g = 0 ; g < map - > objects . size ( ) ; + + g )
{
const ObjectInstanceID gid = ObjectInstanceID ( g ) ;
CGObjectInstance * obj = map - > objects [ g ] ;
if ( obj - > ID ! = Obj : : HERO_PLACEHOLDER )
{
continue ;
}
CGHeroPlaceholder * hp = static_cast < CGHeroPlaceholder * > ( obj ) ;
if ( hp - > subID ! = 0xFF ) //select by type
{
bool found = false ;
2013-06-29 16:05:48 +03:00
for ( auto ghi : Xheroes )
2013-05-29 01:47:15 +03:00
{
if ( ghi - > subID = = hp - > subID )
{
found = true ;
replaceHero ( gid , ghi ) ;
Xheroes - = ghi ;
break ;
}
}
if ( ! found )
{
2013-06-29 16:05:48 +03:00
auto nh = new CGHeroInstance ( ) ;
2013-05-29 01:47:15 +03:00
nh - > initHero ( HeroTypeID ( hp - > subID ) ) ;
replaceHero ( gid , nh ) ;
}
}
}
//selecting heroes by power
std : : sort ( Xheroes . begin ( ) , Xheroes . end ( ) , [ ] ( const CGHeroInstance * a , const CGHeroInstance * b )
{
return a - > getHeroStrength ( ) > b - > getHeroStrength ( ) ;
} ) ; //sort, descending strength
for ( int g = 0 ; g < map - > objects . size ( ) ; + + g )
{
const ObjectInstanceID gid = ObjectInstanceID ( g ) ;
CGObjectInstance * obj = map - > objects [ g ] ;
if ( obj - > ID ! = Obj : : HERO_PLACEHOLDER )
{
continue ;
}
CGHeroPlaceholder * hp = static_cast < CGHeroPlaceholder * > ( obj ) ;
if ( hp - > subID = = 0xFF ) //select by power
{
if ( Xheroes . size ( ) > hp - > power - 1 )
replaceHero ( gid , Xheroes [ hp - > power - 1 ] ) ;
else
{
logGlobal - > warnStream ( ) < < " Warning, no hero to replace! " ;
map - > removeBlockVisTiles ( hp , true ) ;
delete hp ;
2013-06-26 14:18:27 +03:00
map - > objects [ g ] = nullptr ;
2013-05-29 01:47:15 +03:00
}
//we don't have to remove hero from Xheroes because it would destroy the order and duplicates shouldn't happen
}
}
}
return ret ;
}
void CGameState : : placeCampaignHeroes ( const std : : vector < std : : pair < CGHeroInstance * , ObjectInstanceID > > & campHeroReplacements )
{
2013-06-29 16:05:48 +03:00
for ( auto obj : campHeroReplacements )
2013-05-29 01:47:15 +03:00
{
CGHeroPlaceholder * placeholder = dynamic_cast < CGHeroPlaceholder * > ( getObjInstance ( obj . second ) ) ;
CGHeroInstance * heroToPlace = obj . first ;
heroToPlace - > id = obj . second ;
heroToPlace - > tempOwner = placeholder - > tempOwner ;
heroToPlace - > pos = placeholder - > pos ;
heroToPlace - > type = VLC - > heroh - > heroes [ heroToPlace - > type - > ID . getNum ( ) ] ; //TODO is this reasonable? either old type can be still used or it can be deleted?
2013-06-29 16:05:48 +03:00
for ( auto & & i : heroToPlace - > stacks )
2013-05-29 01:47:15 +03:00
i . second - > type = VLC - > creh - > creatures [ i . second - > getCreatureID ( ) ] ;
auto fixArtifact = [ & ] ( CArtifactInstance * art )
{
art - > artType = VLC - > arth - > artifacts [ art - > artType - > id ] ;
gs - > map - > artInstances . push_back ( art ) ;
art - > id = ArtifactInstanceID ( gs - > map - > artInstances . size ( ) - 1 ) ;
} ;
2013-06-29 16:05:48 +03:00
for ( auto & & i : heroToPlace - > artifactsWorn )
2013-05-29 01:47:15 +03:00
fixArtifact ( i . second . artifact ) ;
2013-06-29 16:05:48 +03:00
for ( auto & & i : heroToPlace - > artifactsInBackpack )
2013-05-29 01:47:15 +03:00
fixArtifact ( i . artifact ) ;
map - > heroesOnMap . push_back ( heroToPlace ) ;
map - > objects [ heroToPlace - > id . getNum ( ) ] = heroToPlace ;
map - > addBlockVisTiles ( heroToPlace ) ;
//const auto & travelOptions = scenarioOps->campState->getCurrentScenario().travelOptions;
}
}
bool CGameState : : isUsedHero ( HeroTypeID hid ) const
{
2013-06-29 16:05:48 +03:00
for ( auto hero : map - > heroesOnMap ) //heroes instances initialization
2013-05-29 01:47:15 +03:00
if ( hero - > subID = = hid . getNum ( ) )
return true ;
2013-06-29 16:05:48 +03:00
for ( auto obj : map - > objects ) //prisons
2013-05-29 01:47:15 +03:00
if ( obj & & obj - > ID = = Obj : : PRISON & & obj - > subID = = hid . getNum ( ) )
return true ;
return false ;
}
2009-08-30 15:47:40 +03:00
CGPathNode : : CGPathNode ( )
: coord ( - 1 , - 1 , - 1 )
{
2013-02-06 02:16:13 +03:00
accessible = NOT_SET ;
2009-08-30 15:47:40 +03:00
land = 0 ;
moveRemains = 0 ;
turns = 255 ;
2013-06-26 14:18:27 +03:00
theNodeBefore = nullptr ;
2009-08-30 15:47:40 +03:00
}
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 )
{
2013-06-26 14:18:27 +03:00
hero = nullptr ;
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 )
{
2013-06-29 16:05:48 +03:00
for ( auto & elem : nodes )
2009-09-07 05:29:44 +03:00
{
2013-06-29 16:05:48 +03:00
elem . coord = CGHeroInstance : : convertPosition ( elem . coord , true ) ;
2009-09-07 05:29:44 +03:00
}
}
}
2012-02-16 20:10:58 +03:00
PlayerState : : PlayerState ( )
: color ( - 1 ) , currentSelection ( 0xffffffff ) , enteredWinningCheatCode ( 0 ) ,
2013-02-09 15:56:35 +03:00
enteredLosingCheatCode ( 0 ) , status ( EPlayerStatus : : 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
{
2013-03-03 20:06:03 +03:00
return " Player " + ( color . getNum ( ) < VLC - > generaltexth - > capColors . size ( ) ? VLC - > generaltexth - > capColors [ color . getNum ( ) ] : boost : : lexical_cast < std : : string > ( color ) ) ;
2010-12-12 01:11:26 +02:00
}
2012-06-13 16:04:06 +03:00
InfoAboutArmy : : InfoAboutArmy ( ) :
2013-03-03 20:06:03 +03:00
owner ( PlayerColor : : NEUTRAL )
2012-06-13 16:04:06 +03:00
{ }
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 ) ;
2013-06-26 14:18:27 +03:00
details = ( iah . details ? new Details ( * iah . details ) : nullptr ) ;
2012-06-13 16:04:06 +03:00
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
{
2013-02-06 13:16:44 +03:00
details - > primskills [ i ] = h - > getPrimSkillLevel ( static_cast < PrimarySkill : : PrimarySkill > ( i ) ) ;
2010-02-07 17:06:14 +02:00
}
}
}
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 ( ) ;
2013-02-11 02:24:57 +03:00
details - > customRes = t - > hasBuilt ( BuildingID : : 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
{
2013-06-29 16:05:48 +03:00
for ( auto & elem : army - > Slots ( ) )
2010-12-06 01:10:02 +02:00
{
if ( detailed )
2013-06-29 16:05:48 +03:00
( * this ) [ elem . first ] = * elem . second ;
2010-12-06 01:10:02 +02:00
else
2013-06-29 16:05:48 +03:00
( * this ) [ elem . first ] = CStackBasicDescriptor ( elem . second - > type , elem . second - > getQuantityID ( ) ) ;
2010-12-06 01:10:02 +02:00
}
}
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 )
{
2013-06-29 16:05:48 +03:00
for ( auto & elem : * this )
ret + = elem . second . type - > AIValue * elem . second . count ;
2011-08-25 18:24:37 +03:00
}
else
{
2013-06-29 16:05:48 +03:00
for ( auto & elem : * this )
ret + = elem . second . type - > AIValue * CCreature : : estimateCreatureCount ( elem . second . count ) ;
2011-08-25 18:24:37 +03:00
}
return ret ;
}
2011-01-21 04:36:30 +02:00
DuelParameters : : SideSettings : : StackSettings : : StackSettings ( )
2013-02-07 20:34:50 +03:00
: type ( CreatureID : : NONE ) , count ( 0 )
2011-01-21 04:36:30 +02:00
{
}
2013-02-11 02:24:57 +03:00
DuelParameters : : SideSettings : : StackSettings : : StackSettings ( CreatureID Type , si32 Count )
2011-01-21 04:36:30 +02:00
: type ( Type ) , count ( Count )
{
}
DuelParameters : : SideSettings : : SideSettings ( )
{
heroId = - 1 ;
}
DuelParameters : : DuelParameters ( )
{
2012-10-26 20:51:05 +03:00
terType = ETerrainType : : DIRT ;
2013-02-04 00:05:44 +03:00
bfieldType = BFieldType : : ROCKLANDS ;
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 ) ) ;
2013-02-13 01:24:48 +03:00
ret . terType = ETerrainType ( ( int ) duelData [ " terType " ] . Float ( ) ) ;
ret . bfieldType = BFieldType ( ( int ) duelData [ " bfieldType " ] . Float ( ) ) ;
2013-06-29 16:05:48 +03:00
for ( const JsonNode & n : duelData [ " sides " ] . Vector ( ) )
2012-07-26 03:48:44 +03:00
{
SideSettings & ss = ret . sides [ ( int ) n [ " side " ] . Float ( ) ] ;
int i = 0 ;
2013-06-29 16:05:48 +03:00
for ( const JsonNode & stackNode : n [ " army " ] . Vector ( ) )
2012-07-26 03:48:44 +03:00
{
2013-02-11 02:24:57 +03:00
ss . stacks [ i ] . type = CreatureID ( ( si32 ) stackNode . Vector ( ) [ 0 ] . Float ( ) ) ;
2012-07-26 03:48:44 +03:00
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 ;
2013-06-29 16:05:48 +03:00
for ( const JsonNode & n : n [ " heroPrimSkills " ] . Vector ( ) )
2012-07-26 03:48:44 +03:00
ss . heroPrimSkills . push_back ( n . Float ( ) ) ;
2013-06-29 16:05:48 +03:00
for ( const JsonNode & skillNode : n [ " heroSecSkills " ] . Vector ( ) )
2012-07-26 03:48:44 +03:00
{
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
{
2013-06-29 16:05:48 +03:00
for ( auto spell : VLC - > spellh - > spells )
2013-02-11 02:24:57 +03:00
if ( spell - > id < = SpellID : : 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
2013-06-29 16:05:48 +03:00
for ( const JsonNode & spell : n [ " spells " ] . Vector ( ) )
2013-02-11 02:24:57 +03:00
ss . spells . insert ( SpellID ( spell . Float ( ) ) ) ;
2012-08-01 15:02:54 +03:00
}
2012-07-26 03:48:44 +03:00
}
2013-06-29 16:05:48 +03:00
for ( const JsonNode & n : duelData [ " obstacles " ] . Vector ( ) )
2012-07-26 03:48:44 +03:00
{
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 ) ;
}
2013-06-29 16:05:48 +03:00
for ( const JsonNode & n : duelData [ " creatures " ] . Vector ( ) )
2012-07-26 03:48:44 +03:00
{
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 ) ;
2013-04-19 14:43:11 +03:00
const TerrainTile * tinfo = & gs - > map - > getTile ( int3 ( i , j , k ) ) ;
2011-09-19 23:50:25 +03:00
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 ;
2013-06-26 14:18:27 +03:00
node . theNodeBefore = nullptr ;
2011-09-19 23:50:25 +03:00
}
}
}
}
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
{
2013-04-09 17:31:36 +03:00
logGlobal - > errorStream ( ) < < " CGameState::calculatePaths: Hero outside the gs->map? How dare you... " ;
2011-09-19 23:50:25 +03:00
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 ) ;
2013-06-29 16:05:48 +03:00
for ( auto & neighbour : neighbours )
2011-09-19 23:50:25 +03:00
{
2013-06-29 16:05:48 +03:00
const int3 & n = neighbour ; //current neighbor
2011-09-19 23:50:25 +03:00
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
{
2013-06-29 16:05:48 +03:00
for ( const CGObjectInstance * obj : tinfo - > visitableObjects )
2011-09-19 23:50:25 +03:00
{
2013-04-20 14:34:01 +03:00
if ( obj - > passableFor ( hero - > tempOwner ) ) //special object instance specific passableness flag - overwrites other accessibility flags
2011-09-19 23:50:25 +03:00
{
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
}
2013-03-03 20:06:03 +03:00
CPathfinder : : CPathfinder ( CPathsInfo & _out , CGameState * _gs , const CGHeroInstance * _hero ) : CGameInfoCallback ( _gs , boost : : optional < PlayerColor > ( ) ) , 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
}