2008-06-30 03:06:41 +03:00
# define VCMI_DLL
2010-05-08 21:56:38 +03:00
# include "../hch/CCampaignHandler.h"
2008-06-30 03:06:41 +03:00
# include <algorithm>
# include <queue>
# include <fstream>
2008-02-25 01:06:27 +02:00
# include "CGameState.h"
2008-06-30 03:06:41 +03:00
# include <boost/random/linear_congruential.hpp>
2009-05-20 13:08:56 +03:00
# include "../hch/CDefObjInfoHandler.h"
# include "../hch/CArtHandler.h"
# include "../hch/CBuildingHandler.h"
# include "../hch/CGeneralTextHandler.h"
# include "../hch/CTownHandler.h"
# include "../hch/CSpellHandler.h"
# include "../hch/CHeroHandler.h"
# include "../hch/CObjectHandler.h"
# include "../hch/CCreatureHandler.h"
2010-06-07 08:28:12 +03:00
//#include "../lib/IGameCallback.h"
2009-05-20 13:08:56 +03:00
# include "VCMI_Lib.h"
# include "Connection.h"
2008-06-30 03:06:41 +03:00
# include "map.h"
2009-05-20 13:08:56 +03:00
# include "../StartInfo.h"
# include "NetPacks.h"
2008-07-26 16:57:32 +03:00
# include <boost/foreach.hpp>
2009-07-09 22:15:22 +03:00
# include <boost/lexical_cast.hpp>
2008-07-27 20:07:37 +03:00
# include <boost/thread.hpp>
# include <boost/thread/shared_mutex.hpp>
2009-11-08 16:44:58 +02:00
# include <boost/assign/list_of.hpp>
2009-05-20 13:08:56 +03:00
# include "RegisterTypes.cpp"
2010-04-06 16:19:54 +03:00
# include <algorithm>
# include <numeric>
2009-07-09 22:15:22 +03:00
2008-06-30 03:06:41 +03:00
boost : : rand48 ran ;
2010-06-07 08:28:12 +03:00
class CGObjectInstance ;
2008-02-25 01:06:27 +02:00
2008-09-07 06:38:37 +03:00
# ifdef min
# undef min
# endif
# ifdef max
# undef max
# endif
2008-08-20 09:57:53 +03:00
2009-04-15 17:03:31 +03:00
/*
* CGameState . cpp , part of VCMI engine
*
* Authors : listed in file AUTHORS in main folder
*
* License : GNU General Public License v2 .0 or later
* Full text of license available in license . txt file , in main folder
*
*/
2009-03-15 14:53:58 +02:00
void foofoofoo ( )
{
//never called function to force instantation of templates
int * ccc = NULL ;
registerTypes ( ( CISer < CConnection > & ) * ccc ) ;
registerTypes ( ( COSer < CConnection > & ) * ccc ) ;
registerTypes ( ( CSaveFile & ) * ccc ) ;
registerTypes ( ( CLoadFile & ) * ccc ) ;
registerTypes ( ( CTypeList & ) * ccc ) ;
}
2009-03-07 00:25:19 +02:00
class CBaseForGSApply
{
public :
virtual void applyOnGS ( CGameState * gs , void * pack ) const = 0 ;
2010-01-02 03:48:44 +02:00
virtual ~ CBaseForGSApply ( ) { } ;
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 ) ;
2009-03-19 16:17:19 +02:00
while ( ! gs - > mx - > try_lock ( ) )
boost : : this_thread : : sleep ( boost : : posix_time : : milliseconds ( 50 ) ) ; //give other threads time to finish
2009-03-07 00:25:19 +02:00
ptr - > applyGs ( gs ) ;
2009-03-19 16:17:19 +02:00
gs - > mx - > unlock ( ) ;
2009-03-07 00:25:19 +02:00
}
} ;
class CGSApplier
{
public :
std : : map < ui16 , CBaseForGSApply * > apps ;
CGSApplier ( )
{
registerTypes2 ( * this ) ;
}
2010-01-02 03:48:44 +02:00
~ CGSApplier ( )
{
std : : map < ui16 , CBaseForGSApply * > : : iterator iter ;
for ( iter = apps . begin ( ) ; iter ! = apps . end ( ) ; iter + + )
delete iter - > second ;
}
2009-03-07 00:25:19 +02:00
template < typename T > void registerType ( const T * t = NULL )
{
2009-03-07 17:54:12 +02:00
ui16 ID = typeList . registerType ( t ) ;
2009-03-07 00:25:19 +02:00
apps [ ID ] = new CApplyOnGS < T > ;
}
2009-03-15 17:13:54 +02:00
} * applierGs = NULL ;
2009-03-07 00:25:19 +02:00
2009-09-07 05:29:44 +03:00
class IObjectCaller
{
public :
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 :
std : : vector < IObjectCaller * > apps ;
template < typename T > void registerType ( const T * t = NULL )
{
apps . push_back ( new CObjectCaller < T > ) ;
}
CObjectCallersHandler ( )
{
registerTypes1 ( * this ) ;
}
~ CObjectCallersHandler ( )
{
for ( size_t i = 0 ; i < apps . size ( ) ; i + + )
delete apps [ i ] ;
}
void preInit ( )
{
2010-07-12 13:20:25 +03:00
// for (size_t i = 0; i < apps.size(); i++)
// apps[i]->preInit();
2009-09-07 05:29:44 +03:00
}
void postInit ( )
{
2010-07-12 13:20:25 +03:00
// for (size_t i = 0; i < apps.size(); i++)
// apps[i]->postInit();
2009-09-07 05:29:44 +03:00
}
} * objCaller = NULL ;
2009-07-09 22:15:22 +03:00
void MetaString : : getLocalString ( const std : : pair < ui8 , ui32 > & txt , std : : string & dst ) const
2008-12-27 03:01:59 +02:00
{
2009-07-09 22:15:22 +03:00
int type = txt . first , ser = txt . second ;
if ( type = = ART_NAMES )
{
2010-06-26 19:02:10 +03:00
dst = VLC - > arth - > artifacts [ ser ] - > Name ( ) ;
2009-07-09 22:15:22 +03:00
}
else if ( type = = CRE_PL_NAMES )
{
2010-05-02 21:20:26 +03:00
dst = VLC - > creh - > creatures [ ser ] - > namePl ;
2009-07-09 22:15:22 +03:00
}
else if ( type = = MINE_NAMES )
{
dst = VLC - > generaltexth - > mines [ ser ] . first ;
}
else if ( type = = MINE_EVNTS )
{
dst = VLC - > generaltexth - > mines [ ser ] . second ;
}
else if ( type = = SPELL_NAME )
{
dst = VLC - > spellh - > spells [ ser ] . name ;
}
else if ( type = = CRE_SING_NAMES )
{
2010-05-02 21:20:26 +03:00
dst = VLC - > creh - > creatures [ ser ] - > nameSing ;
2009-07-09 22:15:22 +03:00
}
2010-03-01 20:22:22 +02:00
else if ( type = = ART_DESCR )
{
2010-06-26 19:02:10 +03:00
dst = VLC - > arth - > artifacts [ ser ] - > Description ( ) ;
2010-03-01 20:22:22 +02:00
}
2009-07-09 22:15:22 +03:00
else
2008-12-27 03:01:59 +02:00
{
2009-07-09 22:15:22 +03:00
std : : vector < std : : string > * vec ;
switch ( type )
2008-12-27 03:01:59 +02:00
{
2009-07-09 22:15:22 +03:00
case GENERAL_TXT :
vec = & VLC - > generaltexth - > allTexts ;
break ;
case XTRAINFO_TXT :
vec = & VLC - > generaltexth - > xtrainfo ;
break ;
case OBJ_NAMES :
vec = & VLC - > generaltexth - > names ;
break ;
case RES_NAMES :
vec = & VLC - > generaltexth - > restypes ;
break ;
case ARRAY_TXT :
vec = & VLC - > generaltexth - > arraytxt ;
break ;
case CREGENS :
vec = & VLC - > generaltexth - > creGens ;
break ;
2009-07-26 13:43:22 +03:00
case CREGENS4 :
vec = & VLC - > generaltexth - > creGens4 ;
break ;
2009-07-09 22:15:22 +03:00
case ADVOB_TXT :
vec = & VLC - > generaltexth - > advobtxt ;
break ;
case ART_EVNTS :
vec = & VLC - > generaltexth - > artifEvents ;
break ;
case SEC_SKILL_NAME :
vec = & VLC - > generaltexth - > skillName ;
break ;
2010-02-02 01:30:03 +02:00
case COLOR :
vec = & VLC - > generaltexth - > capColors ;
break ;
2008-12-27 03:01:59 +02:00
}
2009-07-09 22:15:22 +03:00
dst = ( * vec ) [ ser ] ;
}
}
DLL_EXPORT void MetaString : : toString ( std : : string & dst ) const
{
size_t exSt = 0 , loSt = 0 , nums = 0 ;
dst . clear ( ) ;
for ( size_t i = 0 ; i < message . size ( ) ; + + i )
{ //TEXACT_STRING, TLOCAL_STRING, TNUMBER, TREPLACE_ESTRING, TREPLACE_LSTRING, TREPLACE_NUMBER
switch ( message [ i ] )
2008-12-27 03:01:59 +02:00
{
2009-07-09 22:15:22 +03:00
case TEXACT_STRING :
dst + = exactStrings [ exSt + + ] ;
break ;
case TLOCAL_STRING :
2008-12-27 03:01:59 +02:00
{
2009-07-09 22:15:22 +03:00
std : : string hlp ;
getLocalString ( localStrings [ loSt + + ] , hlp ) ;
dst + = hlp ;
2008-12-27 03:01:59 +02:00
}
2009-07-09 22:15:22 +03:00
break ;
case TNUMBER :
dst + = boost : : lexical_cast < std : : string > ( numbers [ nums + + ] ) ;
break ;
case TREPLACE_ESTRING :
2009-09-16 19:16:57 +03:00
dst . replace ( dst . find ( " %s " ) , 2 , exactStrings [ exSt + + ] ) ;
2009-07-09 22:15:22 +03:00
break ;
case TREPLACE_LSTRING :
2008-12-27 03:01:59 +02:00
{
2009-07-09 22:15:22 +03:00
std : : string hlp ;
getLocalString ( localStrings [ loSt + + ] , hlp ) ;
2009-09-16 19:16:57 +03:00
dst . replace ( dst . find ( " %s " ) , 2 , hlp ) ;
2008-12-27 03:01:59 +02:00
}
2009-07-09 22:15:22 +03:00
break ;
case TREPLACE_NUMBER :
2009-09-16 19:16:57 +03:00
dst . replace ( dst . find ( " %d " ) , 2 , boost : : lexical_cast < std : : string > ( numbers [ nums + + ] ) ) ;
2009-07-09 22:15:22 +03:00
break ;
default :
tlog1 < < " MetaString processing error! \n " ;
break ;
2008-12-27 03:01:59 +02:00
}
}
}
2008-10-26 22:58:34 +02:00
2010-07-13 08:25:40 +03:00
DLL_EXPORT std : : string MetaString : : toString ( ) const
{
std : : string ret ;
toString ( ret ) ;
return ret ;
}
2009-09-16 19:16:57 +03:00
DLL_EXPORT std : : string MetaString : : buildList ( ) const
///used to handle loot from creature bank
{
size_t exSt = 0 , loSt = 0 , nums = 0 ;
std : : string lista ;
for ( int i = 0 ; i < message . size ( ) ; + + i )
{
if ( i > 0 & & message [ i ] = = TEXACT_STRING | | message [ i ] = = TLOCAL_STRING )
{
2009-09-17 22:22:47 +03:00
if ( exSt = = exactStrings . size ( ) - 1 )
lista + = VLC - > generaltexth - > allTexts [ 141 ] ; //" and "
2009-09-16 19:16:57 +03:00
else
lista + = " , " ;
}
switch ( message [ i ] )
{
case TEXACT_STRING :
lista + = exactStrings [ exSt + + ] ;
break ;
case TLOCAL_STRING :
{
std : : string hlp ;
getLocalString ( localStrings [ loSt + + ] , hlp ) ;
lista + = hlp ;
}
break ;
case TNUMBER :
lista + = boost : : lexical_cast < std : : string > ( numbers [ nums + + ] ) ;
break ;
case TREPLACE_ESTRING :
lista . replace ( lista . find ( " %s " ) , 2 , exactStrings [ exSt + + ] ) ;
break ;
case TREPLACE_LSTRING :
{
std : : string hlp ;
getLocalString ( localStrings [ loSt + + ] , hlp ) ;
lista . replace ( lista . find ( " %s " ) , 2 , hlp ) ;
}
break ;
case TREPLACE_NUMBER :
lista . replace ( lista . find ( " %d " ) , 2 , boost : : lexical_cast < std : : string > ( numbers [ nums + + ] ) ) ;
break ;
default :
tlog1 < < " MetaString processing error! \n " ;
}
}
return lista ;
}
2010-04-02 05:07:40 +03:00
void MetaString : : addReplacement ( const CStackInstance & stack )
{
assert ( stack . count ) ; //valid count
assert ( stack . type ) ; //valid type
if ( stack . count = = 1 )
addReplacement ( CRE_SING_NAMES , stack . type - > idNumber ) ;
else
addReplacement ( CRE_PL_NAMES , stack . type - > idNumber ) ;
}
2009-05-24 01:57:39 +03:00
static CGObjectInstance * createObject ( int id , int subid , int3 pos , int owner )
2008-07-27 20:07:37 +03:00
{
CGObjectInstance * nobj ;
switch ( id )
{
2009-02-06 16:15:45 +02:00
case HEROI_TYPE : //hero
2008-07-27 20:07:37 +03:00
{
2008-10-26 22:58:34 +02:00
CGHeroInstance * nobj = new CGHeroInstance ( ) ;
2008-07-27 20:07:37 +03:00
nobj - > pos = pos ;
nobj - > tempOwner = owner ;
nobj - > subID = subid ;
2008-10-26 22:58:34 +02:00
//nobj->initHero(ran);
2008-07-27 20:07:37 +03:00
return nobj ;
}
2009-02-06 16:15:45 +02:00
case TOWNI_TYPE : //town
2008-07-27 20:07:37 +03:00
nobj = new CGTownInstance ;
break ;
default : //rest of objects
nobj = new CGObjectInstance ;
nobj - > defInfo = VLC - > dobjinfo - > gobjs [ id ] [ subid ] ;
break ;
}
nobj - > ID = id ;
nobj - > subID = subid ;
if ( ! nobj - > defInfo )
2008-09-19 15:09:15 +03:00
tlog3 < < " No def declaration for " < < id < < " " < < subid < < std : : endl ;
2008-07-27 20:07:37 +03:00
nobj - > pos = pos ;
//nobj->state = NULL;//new CLuaObjectScript();
nobj - > tempOwner = owner ;
nobj - > defInfo - > id = id ;
nobj - > defInfo - > subid = subid ;
//assigning defhandler
2009-02-06 16:15:45 +02:00
if ( nobj - > ID = = HEROI_TYPE | | nobj - > ID = = TOWNI_TYPE )
2008-07-27 20:07:37 +03:00
return nobj ;
nobj - > defInfo = VLC - > dobjinfo - > gobjs [ id ] [ subid ] ;
return nobj ;
}
2009-09-02 17:10:19 +03:00
2009-08-05 15:46:08 +03:00
CStack * BattleInfo : : getStack ( int stackID , bool onlyAlive )
2008-08-05 02:04:15 +03:00
{
2009-05-07 08:01:45 +03:00
for ( unsigned int g = 0 ; g < stacks . size ( ) ; + + g )
2008-08-05 02:04:15 +03:00
{
2009-08-05 15:46:08 +03:00
if ( stacks [ g ] - > ID = = stackID & & ( ! onlyAlive | | stacks [ g ] - > alive ( ) ) )
2008-08-05 02:04:15 +03:00
return stacks [ g ] ;
}
return NULL ;
}
2009-09-02 17:10:19 +03:00
const CStack * BattleInfo : : getStack ( int stackID , bool onlyAlive ) const
{
2009-09-07 05:29:44 +03:00
return const_cast < BattleInfo * const > ( this ) - > getStack ( stackID , onlyAlive ) ;
2009-09-02 17:10:19 +03:00
}
2009-08-05 15:46:08 +03:00
CStack * BattleInfo : : getStackT ( int tileID , bool onlyAlive )
2008-08-05 02:04:15 +03:00
{
2009-05-07 08:01:45 +03:00
for ( unsigned int g = 0 ; g < stacks . size ( ) ; + + g )
2008-08-05 02:04:15 +03:00
{
if ( stacks [ g ] - > position = = tileID
2010-05-02 21:20:26 +03:00
| | ( stacks [ g ] - > doubleWide ( ) & & stacks [ g ] - > attackerOwned & & stacks [ g ] - > position - 1 = = tileID )
| | ( stacks [ g ] - > doubleWide ( ) & & ! stacks [ g ] - > attackerOwned & & stacks [ g ] - > position + 1 = = tileID ) )
2008-08-05 02:04:15 +03:00
{
2009-08-05 15:46:08 +03:00
if ( ! onlyAlive | | stacks [ g ] - > alive ( ) )
2008-08-05 02:04:15 +03:00
{
return stacks [ g ] ;
}
}
}
return NULL ;
}
2009-09-02 17:10:19 +03:00
const CStack * BattleInfo : : getStackT ( int tileID , bool onlyAlive ) const
{
2009-09-07 05:29:44 +03:00
return const_cast < BattleInfo * const > ( this ) - > getStackT ( tileID , onlyAlive ) ;
2009-09-02 17:10:19 +03:00
}
void BattleInfo : : getAccessibilityMap ( bool * accessibility , bool twoHex , bool attackerOwned , bool addOccupiable , std : : set < int > & occupyable , bool flying , int stackToOmmit ) const
2008-08-05 02:04:15 +03:00
{
2009-08-02 17:21:18 +03:00
memset ( accessibility , 1 , BFIELD_SIZE ) ; //initialize array with trues
2009-08-22 15:50:23 +03:00
//removing accessibility for side columns of hexes
for ( int v = 0 ; v < BFIELD_SIZE ; + + v )
{
if ( v % BFIELD_WIDTH = = 0 | | v % BFIELD_WIDTH = = ( BFIELD_WIDTH - 1 ) )
accessibility [ v ] = false ;
}
2009-05-07 08:01:45 +03:00
for ( unsigned int g = 0 ; g < stacks . size ( ) ; + + g )
2008-08-05 02:04:15 +03:00
{
2009-09-04 17:11:42 +03:00
if ( ! stacks [ g ] - > alive ( ) | | stacks [ g ] - > ID = = stackToOmmit | | stacks [ g ] - > position < 0 ) //we don't want to lock position of this stack (eg. if it's a turret)
2008-08-05 02:04:15 +03:00
continue ;
accessibility [ stacks [ g ] - > position ] = false ;
2010-05-02 21:20:26 +03:00
if ( stacks [ g ] - > doubleWide ( ) ) //if it's a double hex creature
2008-08-05 02:04:15 +03:00
{
if ( stacks [ g ] - > attackerOwned )
accessibility [ stacks [ g ] - > position - 1 ] = false ;
else
accessibility [ stacks [ g ] - > position + 1 ] = false ;
}
}
2009-02-09 16:50:32 +02:00
//obstacles
2009-05-07 08:01:45 +03:00
for ( unsigned int b = 0 ; b < obstacles . size ( ) ; + + b )
2009-02-09 16:50:32 +02:00
{
std : : vector < int > blocked = VLC - > heroh - > obstacles [ obstacles [ b ] . ID ] . getBlocked ( obstacles [ b ] . pos ) ;
2009-05-07 08:01:45 +03:00
for ( unsigned int c = 0 ; c < blocked . size ( ) ; + + c )
2009-02-09 16:50:32 +02:00
{
2009-02-14 15:49:30 +02:00
if ( blocked [ c ] > = 0 & & blocked [ c ] < BFIELD_SIZE )
accessibility [ blocked [ c ] ] = false ;
2009-02-09 16:50:32 +02:00
}
}
2009-08-02 17:21:18 +03:00
2009-08-28 13:49:11 +03:00
//walls
2009-08-29 19:22:34 +03:00
if ( siege > 0 )
2009-08-28 13:49:11 +03:00
{
2009-09-02 17:10:19 +03:00
static const int permanentlyLocked [ ] = { 12 , 45 , 78 , 112 , 147 , 165 } ;
2009-08-28 13:49:11 +03:00
for ( int b = 0 ; b < ARRAY_COUNT ( permanentlyLocked ) ; + + b )
{
accessibility [ permanentlyLocked [ b ] ] = false ;
}
2009-08-29 19:08:58 +03:00
static const std : : pair < int , int > lockedIfNotDestroyed [ ] = //(which part of wall, which hex is blocked if this part of wall is not destroyed
2009-09-02 17:10:19 +03:00
{ std : : make_pair ( 2 , 182 ) , std : : make_pair ( 3 , 130 ) , std : : make_pair ( 4 , 62 ) , std : : make_pair ( 5 , 29 ) } ;
2009-08-28 13:49:11 +03:00
for ( int b = 0 ; b < ARRAY_COUNT ( lockedIfNotDestroyed ) ; + + b )
{
if ( si . wallState [ lockedIfNotDestroyed [ b ] . first ] < 3 )
{
accessibility [ lockedIfNotDestroyed [ b ] . second ] = false ;
}
}
2009-09-02 17:10:19 +03:00
//gate
if ( attackerOwned & & si . wallState [ 7 ] < 3 ) //if it attacker's unit and gate is not destroyed
{
accessibility [ 95 ] = accessibility [ 96 ] = false ; //block gate's hexes
}
2009-08-28 13:49:11 +03:00
}
//occupyability
2009-08-02 17:21:18 +03:00
if ( addOccupiable & & twoHex )
{
std : : set < int > rem ; //tiles to unlock
for ( int h = 0 ; h < BFIELD_HEIGHT ; + + h )
{
for ( int w = 1 ; w < BFIELD_WIDTH - 1 ; + + w )
{
int hex = h * BFIELD_WIDTH + w ;
2009-08-04 18:38:26 +03:00
if ( ! isAccessible ( hex , accessibility , twoHex , attackerOwned , flying , true )
& & ( attackerOwned ? isAccessible ( hex + 1 , accessibility , twoHex , attackerOwned , flying , true ) : isAccessible ( hex - 1 , accessibility , twoHex , attackerOwned , flying , true ) )
2009-08-02 17:21:18 +03:00
)
rem . insert ( hex ) ;
}
}
occupyable = rem ;
2009-08-04 18:38:26 +03:00
/*for(std::set<int>::const_iterator it = rem.begin(); it != rem.end(); ++it)
2009-08-02 17:21:18 +03:00
{
accessibility [ * it ] = true ;
2009-08-04 18:38:26 +03:00
} */
2009-08-02 17:21:18 +03:00
}
2008-08-05 02:04:15 +03:00
}
2009-08-02 17:21:18 +03:00
2009-08-04 18:38:26 +03:00
bool BattleInfo : : isAccessible ( int hex , bool * accessibility , bool twoHex , bool attackerOwned , bool flying , bool lastPos )
2009-08-02 17:21:18 +03:00
{
2009-08-04 18:38:26 +03:00
if ( flying & & ! lastPos )
return true ;
2009-08-02 17:21:18 +03:00
if ( twoHex )
{
//if given hex is accessible and appropriate adjacent one is free too
return accessibility [ hex ] & & accessibility [ hex + ( attackerOwned ? - 1 : 1 ) ] ;
}
else
{
return accessibility [ hex ] ;
}
2008-08-05 02:04:15 +03:00
}
2009-08-02 17:21:18 +03:00
2009-09-06 20:46:20 +03:00
void BattleInfo : : makeBFS ( int start , bool * accessibility , int * predecessor , int * dists , bool twoHex , bool attackerOwned , bool flying , bool fillPredecessors ) const //both pointers must point to the at least 187-elements int arrays
2008-08-06 02:33:08 +03:00
{
//inits
2008-11-10 21:06:04 +02:00
for ( int b = 0 ; b < BFIELD_SIZE ; + + b )
2008-08-05 02:04:15 +03:00
predecessor [ b ] = - 1 ;
2008-11-10 21:06:04 +02:00
for ( int g = 0 ; g < BFIELD_SIZE ; + + g )
2008-08-06 02:33:08 +03:00
dists [ g ] = 100000000 ;
2009-09-06 20:46:20 +03:00
std : : queue < std : : pair < int , bool > > hexq ; //bfs queue <hex, accessible> (second filed used only if fillPredecessors is true)
hexq . push ( std : : make_pair ( start , true ) ) ;
dists [ hexq . front ( ) . first ] = 0 ;
2008-08-05 02:04:15 +03:00
int curNext = - 1 ; //for bfs loop only (helper var)
while ( ! hexq . empty ( ) ) //bfs loop
{
2009-09-06 20:46:20 +03:00
std : : pair < int , bool > curHex = hexq . front ( ) ;
std : : vector < int > neighbours = neighbouringTiles ( curHex . first ) ;
2008-08-05 02:04:15 +03:00
hexq . pop ( ) ;
2009-05-07 08:01:45 +03:00
for ( unsigned int nr = 0 ; nr < neighbours . size ( ) ; nr + + )
2008-08-05 02:04:15 +03:00
{
2009-08-02 17:21:18 +03:00
curNext = neighbours [ nr ] ; //if(!accessibility[curNext] || (dists[curHex]+1)>=dists[curNext])
2009-09-06 20:46:20 +03:00
bool accessible = isAccessible ( curNext , accessibility , twoHex , attackerOwned , flying , dists [ curHex . first ] + 1 = = dists [ curNext ] ) ;
if ( dists [ curHex . first ] + 1 > = dists [ curNext ] )
2008-08-06 20:49:47 +03:00
continue ;
2009-09-06 20:46:20 +03:00
if ( accessible & & curHex . second )
2009-09-02 17:10:19 +03:00
{
2009-09-06 20:46:20 +03:00
hexq . push ( std : : make_pair ( curNext , true ) ) ;
dists [ curNext ] = dists [ curHex . first ] + 1 ;
2009-09-02 17:10:19 +03:00
}
2009-09-06 20:46:20 +03:00
else if ( fillPredecessors & & ! ( accessible & & ! curHex . second ) )
{
hexq . push ( std : : make_pair ( curNext , false ) ) ;
dists [ curNext ] = dists [ curHex . first ] + 1 ;
}
predecessor [ curNext ] = curHex . first ;
2008-08-05 02:04:15 +03:00
}
}
2008-08-06 02:33:08 +03:00
} ;
2009-09-02 17:10:19 +03:00
std : : vector < int > BattleInfo : : getAccessibility ( int stackID , bool addOccupiable ) const
2008-08-06 02:33:08 +03:00
{
std : : vector < int > ret ;
2008-11-10 21:06:04 +02:00
bool ac [ BFIELD_SIZE ] ;
2009-10-17 17:32:42 +03:00
const CStack * s = getStack ( stackID , false ) ; //this function is called from healedOrResurrected, so our stack can be dead
2009-09-04 17:11:42 +03:00
if ( s - > position < 0 ) //turrets
return std : : vector < int > ( ) ;
2009-08-02 17:21:18 +03:00
std : : set < int > occupyable ;
2010-05-02 21:20:26 +03:00
getAccessibilityMap ( ac , s - > doubleWide ( ) , s - > attackerOwned , addOccupiable , occupyable , s - > hasBonusOfType ( Bonus : : FLYING ) , stackID ) ;
2008-08-06 02:33:08 +03:00
2008-11-10 21:06:04 +02:00
int pr [ BFIELD_SIZE ] , dist [ BFIELD_SIZE ] ;
2010-05-02 21:20:26 +03:00
makeBFS ( s - > position , ac , pr , dist , s - > doubleWide ( ) , s - > attackerOwned , s - > hasBonusOfType ( Bonus : : FLYING ) , false ) ;
2009-02-14 15:49:30 +02:00
2010-05-02 21:20:26 +03:00
if ( s - > doubleWide ( ) )
2009-02-14 15:49:30 +02:00
{
if ( ! addOccupiable )
{
std : : vector < int > rem ;
for ( int b = 0 ; b < BFIELD_SIZE ; + + b )
{
2009-08-20 13:07:23 +03:00
//don't take into account most left and most right columns of hexes
if ( b % BFIELD_WIDTH = = 0 | | b % BFIELD_WIDTH = = BFIELD_WIDTH - 1 )
continue ;
if ( ac [ b ] & & ! ( s - > attackerOwned ? ac [ b - 1 ] : ac [ b + 1 ] ) )
2009-02-14 15:49:30 +02:00
{
rem . push_back ( b ) ;
}
}
2009-05-07 08:01:45 +03:00
for ( unsigned int g = 0 ; g < rem . size ( ) ; + + g )
2009-02-14 15:49:30 +02:00
{
ac [ rem [ g ] ] = false ;
}
//removing accessibility for side hexes
for ( int v = 0 ; v < BFIELD_SIZE ; + + v )
if ( s - > attackerOwned ? ( v % BFIELD_WIDTH ) = = 1 : ( v % BFIELD_WIDTH ) = = ( BFIELD_WIDTH - 2 ) )
ac [ v ] = false ;
}
}
2008-08-06 02:33:08 +03:00
2009-08-21 22:31:41 +03:00
for ( int i = 0 ; i < BFIELD_SIZE ; + + i ) {
2009-08-02 17:21:18 +03:00
if (
2010-05-02 21:20:26 +03:00
( ( ! addOccupiable & & dist [ i ] < = s - > Speed ( ) & & ac [ i ] ) | | ( addOccupiable & & dist [ i ] < = s - > Speed ( ) & & isAccessible ( i , ac , s - > doubleWide ( ) , s - > attackerOwned , s - > hasBonusOfType ( Bonus : : FLYING ) , true ) ) ) //we can reach it
2009-08-04 18:38:26 +03:00
| | ( vstd : : contains ( occupyable , i ) & & ( dist [ i + ( s - > attackerOwned ? 1 : - 1 ) ] < = s - > Speed ( ) ) & &
ac [ i + ( s - > attackerOwned ? 1 : - 1 ) ] ) //it's occupyable and we can reach adjacent hex
2009-08-02 17:21:18 +03:00
)
2009-02-14 15:49:30 +02:00
{
2008-08-06 02:33:08 +03:00
ret . push_back ( i ) ;
2009-02-14 15:49:30 +02:00
}
2009-08-21 22:31:41 +03:00
}
2008-08-06 02:33:08 +03:00
return ret ;
}
2008-10-11 16:14:52 +03:00
bool BattleInfo : : isStackBlocked ( int ID )
{
CStack * our = getStack ( ID ) ;
2010-05-02 21:20:26 +03:00
if ( our - > hasBonusOfType ( Bonus : : SIEGE_WEAPON ) ) //siege weapons cannot be blocked
2009-09-02 17:10:19 +03:00
return false ;
2009-08-07 12:45:21 +03:00
2009-05-07 08:01:45 +03:00
for ( unsigned int i = 0 ; i < stacks . size ( ) ; i + + )
2008-10-11 16:14:52 +03:00
{
if ( ! stacks [ i ] - > alive ( )
| | stacks [ i ] - > owner = = our - > owner
)
2008-12-08 00:38:04 +02:00
continue ; //we omit dead and allied stacks
2010-05-02 21:20:26 +03:00
if ( stacks [ i ] - > doubleWide ( ) )
2008-11-14 20:18:13 +02:00
{
2008-12-08 00:38:04 +02:00
if ( mutualPosition ( stacks [ i ] - > position , our - > position ) > = 0
| | mutualPosition ( stacks [ i ] - > position + ( stacks [ i ] - > attackerOwned ? - 1 : 1 ) , our - > position ) > = 0 )
2008-11-14 20:18:13 +02:00
return true ;
}
else
{
if ( mutualPosition ( stacks [ i ] - > position , our - > position ) > = 0 )
return true ;
}
2008-10-11 16:14:52 +03:00
}
return false ;
}
2008-08-06 20:49:47 +03:00
signed char BattleInfo : : mutualPosition ( int hex1 , int hex2 )
{
if ( hex2 = = hex1 - ( ( hex1 / 17 ) % 2 ? 18 : 17 ) ) //top left
return 0 ;
if ( hex2 = = hex1 - ( ( hex1 / 17 ) % 2 ? 17 : 16 ) ) //top right
return 1 ;
if ( hex2 = = hex1 - 1 & & hex1 % 17 ! = 0 ) //left
return 5 ;
if ( hex2 = = hex1 + 1 & & hex1 % 17 ! = 16 ) //right
return 2 ;
if ( hex2 = = hex1 + ( ( hex1 / 17 ) % 2 ? 16 : 17 ) ) //bottom left
return 4 ;
if ( hex2 = = hex1 + ( ( hex1 / 17 ) % 2 ? 17 : 18 ) ) //bottom right
return 3 ;
return - 1 ;
}
2009-03-07 18:05:53 +02:00
2008-08-06 20:49:47 +03:00
std : : vector < int > BattleInfo : : neighbouringTiles ( int hex )
{
2008-11-11 17:17:58 +02:00
# define CHECK_AND_PUSH(tile) {int hlp = (tile); if(hlp>=0 && hlp<BFIELD_SIZE && (hlp%BFIELD_WIDTH!=16) && hlp%BFIELD_WIDTH) ret.push_back(hlp);}
2008-08-06 20:49:47 +03:00
std : : vector < int > ret ;
CHECK_AND_PUSH ( hex - ( ( hex / 17 ) % 2 ? 18 : 17 ) ) ;
CHECK_AND_PUSH ( hex - ( ( hex / 17 ) % 2 ? 17 : 16 ) ) ;
CHECK_AND_PUSH ( hex - 1 ) ;
CHECK_AND_PUSH ( hex + 1 ) ;
CHECK_AND_PUSH ( hex + ( ( hex / 17 ) % 2 ? 16 : 17 ) ) ;
CHECK_AND_PUSH ( hex + ( ( hex / 17 ) % 2 ? 17 : 18 ) ) ;
# undef CHECK_AND_PUSH
return ret ;
}
2009-08-02 17:21:18 +03:00
std : : pair < std : : vector < int > , int > BattleInfo : : getPath ( int start , int dest , bool * accessibility , bool flyingCreature , bool twoHex , bool attackerOwned )
2008-08-06 02:33:08 +03:00
{
2008-11-10 21:06:04 +02:00
int predecessor [ BFIELD_SIZE ] ; //for getting the Path
int dist [ BFIELD_SIZE ] ; //calculated distances
2008-08-05 02:04:15 +03:00
2009-09-06 20:46:20 +03:00
makeBFS ( start , accessibility , predecessor , dist , twoHex , attackerOwned , flyingCreature , false ) ;
2009-08-03 17:29:29 +03:00
if ( predecessor [ dest ] = = - 1 ) //cannot reach destination
{
return std : : make_pair ( std : : vector < int > ( ) , 0 ) ;
}
2008-08-06 02:33:08 +03:00
//making the Path
2008-08-05 02:04:15 +03:00
std : : vector < int > path ;
int curElem = dest ;
while ( curElem ! = start )
{
path . push_back ( curElem ) ;
curElem = predecessor [ curElem ] ;
}
2009-03-07 18:05:53 +02:00
return std : : make_pair ( path , dist [ dest ] ) ;
2008-08-05 02:04:15 +03:00
}
2010-05-02 21:20:26 +03:00
CStack : : CStack ( const CStackInstance * base , int O , int I , bool AO , int S )
: CStackInstance ( * base ) , ID ( I ) , owner ( O ) , slot ( S ) , attackerOwned ( AO ) , position ( - 1 ) ,
counterAttacks ( 1 )
2009-05-08 19:55:04 +03:00
{
2010-05-02 21:20:26 +03:00
baseAmount = base - > count ;
firstHPleft = valOfBonuses ( Bonus : : STACK_HEALTH ) ;
shots = type - > shots ;
counterAttacks + = valOfBonuses ( Bonus : : ADDITIONAL_RETALIATION ) ;
2009-05-08 19:55:04 +03:00
2009-08-17 14:22:29 +03:00
//alive state indication
2008-09-12 11:51:46 +03:00
state . insert ( ALIVE ) ;
2008-06-30 03:06:41 +03:00
}
2008-11-01 00:41:22 +02:00
2009-09-20 15:47:40 +03:00
ui32 CStack : : Speed ( int turn /*= 0*/ ) const
2008-11-09 00:29:19 +02:00
{
2010-05-02 21:20:26 +03:00
if ( hasBonus ( Selector : : type ( Bonus : : SIEGE_WEAPON ) & & Selector : : turns ( turn ) ) ) //war machines cannot move
2009-07-26 15:15:38 +03:00
return 0 ;
2010-05-02 21:20:26 +03:00
int speed = valOfBonuses ( Selector : : type ( Bonus : : STACKS_SPEED ) & & Selector : : turns ( turn ) ) ;
2009-05-17 18:24:50 +03:00
int percentBonus = 0 ;
2010-05-02 21:20:26 +03:00
BOOST_FOREACH ( const Bonus & b , bonuses )
2009-05-17 18:24:50 +03:00
{
2010-05-02 21:20:26 +03:00
if ( b . type = = Bonus : : STACKS_SPEED )
2009-05-17 18:24:50 +03:00
{
2010-05-02 21:20:26 +03:00
percentBonus + = b . additionalInfo ;
2009-05-17 18:24:50 +03:00
}
}
2009-10-17 17:53:16 +03:00
speed = ( ( 100 + percentBonus ) * speed ) / 100 ;
2009-05-17 18:24:50 +03:00
2008-11-09 00:29:19 +02:00
//bind effect check
2009-05-17 18:24:50 +03:00
if ( getEffect ( 72 ) )
2009-02-14 17:00:29 +02:00
{
2009-05-17 18:24:50 +03:00
return 0 ;
2009-02-14 17:00:29 +02:00
}
2009-05-17 18:24:50 +03:00
return speed ;
2008-11-09 00:29:19 +02:00
}
2009-09-20 15:47:40 +03:00
const CStack : : StackEffect * CStack : : getEffect ( ui16 id , int turn /*= 0*/ ) const
2008-11-09 00:29:19 +02:00
{
2009-05-07 08:01:45 +03:00
for ( unsigned int i = 0 ; i < effects . size ( ) ; i + + )
2008-11-09 00:29:19 +02:00
if ( effects [ i ] . id = = id )
2009-09-20 15:47:40 +03:00
if ( ! turn | | effects [ i ] . turnsRemain > turn )
return & effects [ i ] ;
2008-11-09 00:29:19 +02:00
return NULL ;
}
2009-02-05 11:49:45 +02:00
2009-04-21 20:32:43 +03:00
ui8 CStack : : howManyEffectsSet ( ui16 id ) const
{
ui8 ret = 0 ;
2009-05-07 08:01:45 +03:00
for ( unsigned int i = 0 ; i < effects . size ( ) ; i + + )
2009-04-21 20:32:43 +03:00
if ( effects [ i ] . id = = id ) //effect found
{
+ + ret ;
}
return ret ;
}
2009-09-20 15:47:40 +03:00
bool CStack : : willMove ( int turn /*= 0*/ ) const
2009-03-29 15:02:37 +03:00
{
2009-09-20 15:47:40 +03:00
return ( turn ? true : ! vstd : : contains ( state , DEFENDING ) )
& & ! moved ( turn )
& & canMove ( turn ) ;
2009-09-07 05:29:44 +03:00
}
2009-09-20 15:47:40 +03:00
bool CStack : : canMove ( int turn /*= 0*/ ) const
2009-09-07 05:29:44 +03:00
{
return alive ( )
2010-05-02 21:20:26 +03:00
& & ! hasBonus ( Selector : : type ( Bonus : : NOT_ACTIVE ) & & Selector : : turns ( turn ) ) ; //eg. Ammo Cart or blinded creature
2009-03-29 15:02:37 +03:00
}
2009-09-20 15:47:40 +03:00
bool CStack : : moved ( int turn /*= 0*/ ) const
2009-09-07 05:29:44 +03:00
{
2009-09-20 15:47:40 +03:00
if ( ! turn )
return vstd : : contains ( state , MOVED ) ;
else
return false ;
2009-09-07 05:29:44 +03:00
}
2010-05-02 21:20:26 +03:00
bool CStack : : doubleWide ( ) const
{
return type - > doubleWide ;
}
2010-07-28 15:31:34 +03:00
int CStack : : occupiedHex ( ) const
{
if ( doubleWide ( ) )
{
if ( attackerOwned )
return position - 1 ;
else
return position + 1 ;
}
else
{
return - 1 ;
}
}
2010-07-08 08:52:11 +03:00
CGHeroInstance * CGameState : : HeroesPool : : pickHeroFor ( bool native , int player , const CTown * town , std : : map < ui32 , CGHeroInstance * > & available , const CHeroClass * bannedClass /*= NULL*/ ) const
2008-11-01 00:41:22 +02:00
{
2009-08-05 03:05:37 +03:00
CGHeroInstance * ret = NULL ;
2008-11-01 00:41:22 +02:00
if ( player < 0 | | player > = PLAYER_LIMIT )
{
2008-12-22 19:48:41 +02:00
tlog1 < < " Cannot pick hero for " < < town - > Name ( ) < < " . Wrong owner! \n " ;
2008-11-01 00:41:22 +02:00
return NULL ;
}
2009-08-05 03:05:37 +03:00
2008-11-01 00:41:22 +02:00
std : : vector < CGHeroInstance * > pool ;
2009-08-05 03:05:37 +03:00
2008-11-01 00:41:22 +02:00
if ( native )
{
2009-08-05 03:05:37 +03:00
for ( std : : map < ui32 , CGHeroInstance * > : : iterator i = available . begin ( ) ; i ! = available . end ( ) ; i + + )
2008-11-01 00:41:22 +02:00
{
2009-08-05 03:05:37 +03:00
if ( pavailable . find ( i - > first ) - > second & 1 < < player
& & i - > second - > type - > heroType / 2 = = town - > typeID )
2008-11-01 00:41:22 +02:00
{
2009-11-15 16:06:25 +02:00
pool . push_back ( i - > second ) ; //get all avaliable heroes
2008-11-01 00:41:22 +02:00
}
}
if ( ! pool . size ( ) )
2009-08-05 03:05:37 +03:00
{
tlog1 < < " Cannot pick native hero for " < < player < < " . Picking any... \n " ;
return pickHeroFor ( false , player , town , available ) ;
}
2008-11-01 00:41:22 +02:00
else
2009-08-05 03:05:37 +03:00
{
ret = pool [ rand ( ) % pool . size ( ) ] ;
}
2008-11-01 00:41:22 +02:00
}
else
{
2009-08-05 03:05:37 +03:00
int sum = 0 , r ;
for ( std : : map < ui32 , CGHeroInstance * > : : iterator i = available . begin ( ) ; i ! = available . end ( ) ; i + + )
2008-11-01 00:41:22 +02:00
{
2010-07-08 08:52:11 +03:00
if ( pavailable . find ( i - > first ) - > second & 1 < < player
& & ! bannedClass | | i - > second - > type - > heroClass ! = bannedClass )
2008-11-01 00:41:22 +02:00
{
pool . push_back ( i - > second ) ;
2009-11-15 16:06:25 +02:00
sum + = i - > second - > type - > heroClass - > selectionProbability [ town - > typeID ] ; //total weight
2008-11-01 00:41:22 +02:00
}
}
if ( ! pool . size ( ) )
{
tlog1 < < " There are no heroes available for player " < < player < < " ! \n " ;
return NULL ;
}
2009-08-05 03:05:37 +03:00
2008-11-01 00:41:22 +02:00
r = rand ( ) % sum ;
2009-11-15 16:06:25 +02:00
for ( unsigned int i = 0 ; i < pool . size ( ) ; i + + )
2008-11-01 00:41:22 +02:00
{
r - = pool [ i ] - > type - > heroClass - > selectionProbability [ town - > typeID ] ;
2009-11-15 16:06:25 +02:00
if ( r < 0 )
{
2009-08-05 03:05:37 +03:00
ret = pool [ i ] ;
2009-11-15 16:06:25 +02:00
break ;
}
2008-11-01 00:41:22 +02:00
}
2009-08-05 03:05:37 +03:00
if ( ! ret )
ret = pool . back ( ) ;
2008-11-01 00:41:22 +02:00
}
2009-08-05 03:05:37 +03:00
available . erase ( ret - > subID ) ;
return ret ;
2008-11-01 00:41:22 +02:00
}
2009-08-05 03:05:37 +03:00
2009-03-07 00:11:17 +02:00
//void CGameState::apply(CPack * pack)
//{
// while(!mx->try_lock())
// boost::this_thread::sleep(boost::posix_time::milliseconds(50)); //give other threads time to finish
// //applyNL(pack);
// mx->unlock();
//}
2008-06-30 03:06:41 +03:00
int CGameState : : pickHero ( int owner )
{
int h = - 1 ;
2008-08-30 00:41:32 +03:00
if ( ! map - > getHero ( h = scenarioOps - > getIthPlayersSettings ( owner ) . hero , 0 ) & & h > = 0 ) //we haven't used selected hero
2008-06-30 03:06:41 +03:00
return h ;
int f = scenarioOps - > getIthPlayersSettings ( owner ) . castle ;
int i = 0 ;
do //try to find free hero of our faction
{
i + + ;
h = scenarioOps - > getIthPlayersSettings ( owner ) . castle * HEROES_PER_TYPE * 2 + ( ran ( ) % ( HEROES_PER_TYPE * 2 ) ) ; //->scenarioOps->playerInfos[pru].hero = VLC->
} while ( map - > getHero ( h ) & & i < 175 ) ;
if ( i > 174 ) //probably no free heroes - there's no point in further search, we'll take first free
{
2008-09-19 15:09:15 +03:00
tlog3 < < " Warning: cannot find free hero - trying to get first available... " < < std : : endl ;
2008-06-30 03:06:41 +03:00
for ( int j = 0 ; j < HEROES_PER_TYPE * 2 * F_NUMBER ; j + + )
if ( ! map - > getHero ( j ) )
h = j ;
}
return h ;
}
2008-08-04 18:56:36 +03:00
CGHeroInstance * CGameState : : getHero ( int objid )
{
2009-08-17 16:08:05 +03:00
if ( objid < 0 | | objid > = map - > objects . size ( ) | | map - > objects [ objid ] - > ID ! = HEROI_TYPE )
2008-08-04 18:56:36 +03:00
return NULL ;
return static_cast < CGHeroInstance * > ( map - > objects [ objid ] ) ;
}
2010-01-29 22:52:45 +02:00
const CGHeroInstance * CGameState : : getHero ( int objid ) const
{
return ( const_cast < CGameState * > ( this ) ) - > getHero ( objid ) ;
}
2008-08-13 12:28:06 +03:00
CGTownInstance * CGameState : : getTown ( int objid )
{
if ( objid < 0 | | objid > = map - > objects . size ( ) )
return NULL ;
2010-07-09 02:03:27 +03:00
CGObjectInstance * obj = map - > objects [ objid ] ;
if ( obj - > ID ! = TOWNI_TYPE )
return NULL ;
return static_cast < CGTownInstance * > ( obj ) ;
2008-08-13 12:28:06 +03:00
}
2010-01-29 22:52:45 +02:00
const CGTownInstance * CGameState : : getTown ( int objid ) const
{
return ( const_cast < CGameState * > ( this ) ) - > getTown ( objid ) ;
}
2009-10-26 11:11:10 +02:00
std : : pair < int , int > CGameState : : pickObject ( CGObjectInstance * obj )
2008-02-25 01:06:27 +02:00
{
2008-06-30 03:06:41 +03:00
switch ( obj - > ID )
{
2010-07-09 08:07:56 +03:00
case 65 :
2010-06-28 08:07:21 +03:00
return std : : pair < int , int > ( 5 , VLC - > arth - > getRandomArt ( CArtifact : : ART_TREASURE | CArtifact : : ART_MINOR | CArtifact : : ART_MAJOR | CArtifact : : ART_RELIC ) ) ;
2009-10-26 11:11:10 +02:00
case 66 : //random treasure artifact
2010-06-28 08:07:21 +03:00
return std : : pair < int , int > ( 5 , VLC - > arth - > getRandomArt ( CArtifact : : ART_TREASURE ) ) ;
2009-10-26 11:11:10 +02:00
case 67 : //random minor artifact
2010-06-28 08:07:21 +03:00
return std : : pair < int , int > ( 5 , VLC - > arth - > getRandomArt ( CArtifact : : ART_MINOR ) ) ;
2009-10-26 11:11:10 +02:00
case 68 : //random major artifact
2010-06-28 08:07:21 +03:00
return std : : pair < int , int > ( 5 , VLC - > arth - > getRandomArt ( CArtifact : : ART_MAJOR ) ) ;
2009-10-26 11:11:10 +02:00
case 69 : //random relic artifact
2010-06-28 08:07:21 +03:00
return std : : pair < int , int > ( 5 , VLC - > arth - > getRandomArt ( CArtifact : : ART_RELIC ) ) ;
2008-06-30 03:06:41 +03:00
case 70 : //random hero
{
2009-02-06 16:15:45 +02:00
return std : : pair < int , int > ( HEROI_TYPE , pickHero ( obj - > tempOwner ) ) ;
2008-06-30 03:06:41 +03:00
}
case 71 : //random monster
2008-08-30 00:41:32 +03:00
{
2010-07-24 00:05:49 +03:00
return std : : pair < int , int > ( 54 , VLC - > creh - > pickRandomMonster ( boost : : ref ( ran ) ) ) ;
2008-08-30 00:41:32 +03:00
}
2008-06-30 03:06:41 +03:00
case 72 : //random monster lvl1
return std : : pair < int , int > ( 54 , VLC - > creh - > levelCreatures [ 1 ] [ ran ( ) % VLC - > creh - > levelCreatures [ 1 ] . size ( ) ] - > idNumber ) ;
case 73 : //random monster lvl2
return std : : pair < int , int > ( 54 , VLC - > creh - > levelCreatures [ 2 ] [ ran ( ) % VLC - > creh - > levelCreatures [ 2 ] . size ( ) ] - > idNumber ) ;
case 74 : //random monster lvl3
return std : : pair < int , int > ( 54 , VLC - > creh - > levelCreatures [ 3 ] [ ran ( ) % VLC - > creh - > levelCreatures [ 3 ] . size ( ) ] - > idNumber ) ;
case 75 : //random monster lvl4
return std : : pair < int , int > ( 54 , VLC - > creh - > levelCreatures [ 4 ] [ ran ( ) % VLC - > creh - > levelCreatures [ 4 ] . size ( ) ] - > idNumber ) ;
case 76 : //random resource
return std : : pair < int , int > ( 79 , ran ( ) % 7 ) ; //now it's OH3 style, use %8 for mithril
case 77 : //random town
{
2009-05-01 17:37:25 +03:00
int align = ( static_cast < CGTownInstance * > ( obj ) ) - > alignment ,
2008-06-30 03:06:41 +03:00
f ;
if ( align > PLAYER_LIMIT - 1 ) //same as owner / random
{
if ( obj - > tempOwner > PLAYER_LIMIT - 1 )
f = - 1 ; //random
else
f = scenarioOps - > getIthPlayersSettings ( obj - > tempOwner ) . castle ;
}
else
{
f = scenarioOps - > getIthPlayersSettings ( align ) . castle ;
}
if ( f < 0 ) f = ran ( ) % VLC - > townh - > towns . size ( ) ;
2009-02-06 16:15:45 +02:00
return std : : pair < int , int > ( TOWNI_TYPE , f ) ;
2008-06-30 03:06:41 +03:00
}
case 162 : //random monster lvl5
return std : : pair < int , int > ( 54 , VLC - > creh - > levelCreatures [ 5 ] [ ran ( ) % VLC - > creh - > levelCreatures [ 5 ] . size ( ) ] - > idNumber ) ;
case 163 : //random monster lvl6
return std : : pair < int , int > ( 54 , VLC - > creh - > levelCreatures [ 6 ] [ ran ( ) % VLC - > creh - > levelCreatures [ 6 ] . size ( ) ] - > idNumber ) ;
case 164 : //random monster lvl7
return std : : pair < int , int > ( 54 , VLC - > creh - > levelCreatures [ 7 ] [ ran ( ) % VLC - > creh - > levelCreatures [ 7 ] . size ( ) ] - > idNumber ) ;
case 216 : //random dwelling
{
int faction = ran ( ) % F_NUMBER ;
2010-02-21 20:07:24 +02:00
CGDwelling * dwl = static_cast < CGDwelling * > ( obj ) ;
CCreGen2ObjInfo * info = static_cast < CCreGen2ObjInfo * > ( dwl - > info ) ;
2008-06-30 03:06:41 +03:00
if ( info - > asCastle )
{
2009-05-07 08:01:45 +03:00
for ( unsigned int i = 0 ; i < map - > objects . size ( ) ; i + + )
2008-06-30 03:06:41 +03:00
{
if ( map - > objects [ i ] - > ID = = 77 & & dynamic_cast < CGTownInstance * > ( map - > objects [ i ] ) - > identifier = = info - > identifier )
{
randomizeObject ( map - > objects [ i ] ) ; //we have to randomize the castle first
faction = map - > objects [ i ] - > subID ;
break ;
}
2009-02-06 16:15:45 +02:00
else if ( map - > objects [ i ] - > ID = = TOWNI_TYPE & & dynamic_cast < CGTownInstance * > ( map - > objects [ i ] ) - > identifier = = info - > identifier )
2008-06-30 03:06:41 +03:00
{
faction = map - > objects [ i ] - > subID ;
break ;
}
}
}
else
{
while ( ( ! ( info - > castles [ 0 ] & ( 1 < < faction ) ) ) )
{
if ( ( faction > 7 ) & & ( info - > castles [ 1 ] & ( 1 < < ( faction - 8 ) ) ) )
break ;
faction = ran ( ) % F_NUMBER ;
}
}
int level = ( ( info - > maxLevel - info - > minLevel ) ? ( ran ( ) % ( info - > maxLevel - info - > minLevel ) + info - > minLevel ) : ( info - > minLevel ) ) ;
int cid = VLC - > townh - > towns [ faction ] . basicCreatures [ level ] ;
2009-05-07 08:01:45 +03:00
for ( unsigned int i = 0 ; i < VLC - > objh - > cregens . size ( ) ; i + + )
2008-06-30 03:06:41 +03:00
if ( VLC - > objh - > cregens [ i ] = = cid )
return std : : pair < int , int > ( 17 , i ) ;
2009-11-13 18:02:25 +02:00
tlog3 < < " Cannot find a dwelling for creature " < < cid < < std : : endl ;
2010-02-21 20:07:24 +02:00
return std : : pair < int , int > ( 17 , 0 ) ;
delete dwl - > info ;
dwl - > info = NULL ;
2008-06-30 03:06:41 +03:00
}
case 217 :
{
int faction = ran ( ) % F_NUMBER ;
2010-02-21 20:07:24 +02:00
CGDwelling * dwl = static_cast < CGDwelling * > ( obj ) ;
CCreGenObjInfo * info = static_cast < CCreGenObjInfo * > ( dwl - > info ) ;
2008-06-30 03:06:41 +03:00
if ( info - > asCastle )
{
2009-05-07 08:01:45 +03:00
for ( unsigned int i = 0 ; i < map - > objects . size ( ) ; i + + )
2008-06-30 03:06:41 +03:00
{
if ( map - > objects [ i ] - > ID = = 77 & & dynamic_cast < CGTownInstance * > ( map - > objects [ i ] ) - > identifier = = info - > identifier )
{
randomizeObject ( map - > objects [ i ] ) ; //we have to randomize the castle first
faction = map - > objects [ i ] - > subID ;
break ;
}
2009-02-06 16:15:45 +02:00
else if ( map - > objects [ i ] - > ID = = TOWNI_TYPE & & dynamic_cast < CGTownInstance * > ( map - > objects [ i ] ) - > identifier = = info - > identifier )
2008-06-30 03:06:41 +03:00
{
faction = map - > objects [ i ] - > subID ;
break ;
}
}
}
else
{
while ( ( ! ( info - > castles [ 0 ] & ( 1 < < faction ) ) ) )
{
if ( ( faction > 7 ) & & ( info - > castles [ 1 ] & ( 1 < < ( faction - 8 ) ) ) )
break ;
faction = ran ( ) % F_NUMBER ;
}
}
int cid = VLC - > townh - > towns [ faction ] . basicCreatures [ obj - > subID ] ;
2009-05-07 08:01:45 +03:00
for ( unsigned int i = 0 ; i < VLC - > objh - > cregens . size ( ) ; i + + )
2008-06-30 03:06:41 +03:00
if ( VLC - > objh - > cregens [ i ] = = cid )
return std : : pair < int , int > ( 17 , i ) ;
2008-09-19 15:09:15 +03:00
tlog3 < < " Cannot find a dwelling for creature " < < cid < < std : : endl ;
2010-02-21 20:07:24 +02:00
return std : : pair < int , int > ( 17 , 0 ) ;
delete dwl - > info ;
dwl - > info = NULL ;
2008-06-30 03:06:41 +03:00
}
case 218 :
{
2010-02-21 20:07:24 +02:00
CGDwelling * dwl = static_cast < CGDwelling * > ( obj ) ;
CCreGen3ObjInfo * info = static_cast < CCreGen3ObjInfo * > ( dwl - > info ) ;
2008-06-30 03:06:41 +03:00
int level = ( ( info - > maxLevel - info - > minLevel ) ? ( ran ( ) % ( info - > maxLevel - info - > minLevel ) + info - > minLevel ) : ( info - > minLevel ) ) ;
int cid = VLC - > townh - > towns [ obj - > subID ] . basicCreatures [ level ] ;
2009-05-07 08:01:45 +03:00
for ( unsigned int i = 0 ; i < VLC - > objh - > cregens . size ( ) ; i + + )
2008-06-30 03:06:41 +03:00
if ( VLC - > objh - > cregens [ i ] = = cid )
return std : : pair < int , int > ( 17 , i ) ;
2008-09-19 15:09:15 +03:00
tlog3 < < " Cannot find a dwelling for creature " < < cid < < std : : endl ;
2008-06-30 03:06:41 +03:00
return std : : pair < int , int > ( 17 , 0 ) ;
2010-02-21 20:07:24 +02:00
delete dwl - > info ;
dwl - > info = NULL ;
2008-06-30 03:06:41 +03:00
}
}
return std : : pair < int , int > ( - 1 , - 1 ) ;
}
2010-01-01 20:54:31 +02:00
2008-06-30 03:06:41 +03:00
void CGameState : : randomizeObject ( CGObjectInstance * cur )
{
std : : pair < int , int > ran = pickObject ( cur ) ;
if ( ran . first < 0 | | ran . second < 0 ) //this is not a random object, or we couldn't find anything
{
2009-02-06 16:15:45 +02:00
if ( cur - > ID = = TOWNI_TYPE ) //town - set def
2008-06-30 03:06:41 +03:00
{
CGTownInstance * t = dynamic_cast < CGTownInstance * > ( cur ) ;
2010-01-29 22:52:45 +02:00
t - > town = & VLC - > townh - > towns [ t - > subID ] ;
2008-06-30 03:06:41 +03:00
if ( t - > hasCapitol ( ) )
t - > defInfo = capitols [ t - > subID ] ;
else if ( t - > hasFort ( ) )
t - > defInfo = forts [ t - > subID ] ;
else
t - > defInfo = villages [ t - > subID ] ;
}
return ;
}
2009-02-06 16:15:45 +02:00
else if ( ran . first = = HEROI_TYPE ) //special code for hero
2008-06-30 03:06:41 +03:00
{
CGHeroInstance * h = dynamic_cast < CGHeroInstance * > ( cur ) ;
2008-09-19 15:09:15 +03:00
if ( ! h ) { tlog2 < < " Wrong random hero at " < < cur - > pos < < std : : endl ; return ; }
2008-06-30 03:06:41 +03:00
cur - > ID = ran . first ;
2008-08-06 01:11:32 +03:00
h - > portrait = cur - > subID = ran . second ;
2008-06-30 03:06:41 +03:00
h - > type = VLC - > heroh - > heroes [ ran . second ] ;
2010-05-02 21:20:26 +03:00
h - > randomizeArmy ( h - > type - > heroType / 2 ) ;
2008-06-30 03:06:41 +03:00
map - > heroes . push_back ( h ) ;
return ; //TODO: maybe we should do something with definfo?
}
2009-02-06 16:15:45 +02:00
else if ( ran . first = = TOWNI_TYPE ) //special code for town
2008-06-30 03:06:41 +03:00
{
CGTownInstance * t = dynamic_cast < CGTownInstance * > ( cur ) ;
2008-09-19 15:09:15 +03:00
if ( ! t ) { tlog2 < < " Wrong random town at " < < cur - > pos < < std : : endl ; return ; }
2008-06-30 03:06:41 +03:00
cur - > ID = ran . first ;
cur - > subID = ran . second ;
t - > town = & VLC - > townh - > towns [ ran . second ] ;
if ( t - > hasCapitol ( ) )
t - > defInfo = capitols [ t - > subID ] ;
else if ( t - > hasFort ( ) )
t - > defInfo = forts [ t - > subID ] ;
else
t - > defInfo = villages [ t - > subID ] ;
2010-05-02 21:20:26 +03:00
t - > randomizeArmy ( t - > subID ) ;
2008-06-30 03:06:41 +03:00
map - > towns . push_back ( t ) ;
return ;
}
//we have to replace normal random object
cur - > ID = ran . first ;
cur - > subID = ran . second ;
2009-02-11 19:03:30 +02:00
map - > removeBlockVisTiles ( cur ) ; //recalculate blockvis tiles - picked object might have different than random placeholder
2009-01-06 20:42:20 +02:00
map - > defy . push_back ( cur - > defInfo = VLC - > dobjinfo - > gobjs [ ran . first ] [ ran . second ] ) ;
2008-08-06 01:11:32 +03:00
if ( ! cur - > defInfo )
{
2008-09-19 15:09:15 +03:00
tlog1 < < " *BIG* WARNING: Missing def declaration for " < < cur - > ID < < " " < < cur - > subID < < std : : endl ;
2008-08-06 01:11:32 +03:00
return ;
}
2009-02-11 19:03:30 +02:00
map - > addBlockVisTiles ( cur ) ;
2008-06-30 03:06:41 +03:00
}
2008-07-25 20:28:28 +03:00
int CGameState : : getDate ( int mode ) const
{
int temp ;
switch ( mode )
{
2010-06-29 12:59:14 +03:00
case 0 : //day number
2008-07-25 20:28:28 +03:00
return day ;
break ;
2010-06-29 12:59:14 +03:00
case 1 : //day of week
2008-07-25 20:28:28 +03:00
temp = ( day ) % 7 ;
if ( temp )
return temp ;
else return 7 ;
break ;
2010-06-29 12:59:14 +03:00
case 2 : //current week
2008-07-25 20:28:28 +03:00
temp = ( ( day - 1 ) / 7 ) + 1 ;
if ( ! ( temp % 4 ) )
return 4 ;
else
return ( temp % 4 ) ;
break ;
2010-06-29 12:59:14 +03:00
case 3 : //current month
return ( ( day - 1 ) / 28 ) + 1 ;
2008-07-25 20:28:28 +03:00
break ;
}
return 0 ;
}
2008-07-27 20:07:37 +03:00
CGameState : : CGameState ( )
{
mx = new boost : : shared_mutex ( ) ;
2009-01-11 00:08:18 +02:00
map = NULL ;
curB = NULL ;
scenarioOps = NULL ;
2009-03-15 17:13:54 +02:00
applierGs = new CGSApplier ;
2009-09-07 05:29:44 +03:00
objCaller = new CObjectCallersHandler ;
2010-05-08 21:56:38 +03:00
campaign = NULL ;
2008-07-27 20:07:37 +03:00
}
CGameState : : ~ CGameState ( )
{
delete mx ;
2009-01-11 00:08:18 +02:00
delete map ;
delete curB ;
2010-05-27 01:54:00 +03:00
//delete scenarioOps;
2009-03-15 17:13:54 +02:00
delete applierGs ;
2009-09-07 05:29:44 +03:00
delete objCaller ;
2008-07-27 20:07:37 +03:00
}
2010-05-08 21:56:38 +03:00
void CGameState : : init ( StartInfo * si , ui32 checksum , int Seed )
2008-06-30 03:06:41 +03:00
{
2010-07-26 23:56:39 +03:00
VLC - > arth - > allowedArtifacts . clear ( ) ;
VLC - > arth - > clearHlpLists ( ) ;
2010-05-08 21:56:38 +03:00
switch ( si - > mode )
{
case 0 :
map = new Mapa ( si - > mapname ) ;
2010-06-28 08:07:21 +03:00
for ( int i = 0 ; i < 144 ; + + i ) //yes, 144
{
if ( map - > allowedArtifact [ i ] )
VLC - > arth - > allowedArtifacts . push_back ( VLC - > arth - > artifacts [ i ] ) ;
}
2010-05-08 21:56:38 +03:00
break ;
case 2 :
campaign = new CCampaignState ( ) ;
campaign - > initNewCampaign ( * si ) ;
std : : string & mapContent = campaign - > camp - > mapPieces [ si - > whichMapInCampaign ] ;
map = new Mapa ( ) ;
map - > initFromBytes ( ( const unsigned char * ) mapContent . c_str ( ) ) ;
2010-06-28 08:07:21 +03:00
for ( int i = 0 ; i < 144 ; + + i )
{
if ( map - > allowedArtifact [ i ] )
VLC - > arth - > allowedArtifacts . push_back ( VLC - > arth - > artifacts [ i ] ) ;
}
2010-05-08 21:56:38 +03:00
break ;
}
tlog0 < < " Map loaded! " < < std : : endl ;
//tlog0 <<"Reading and detecting map file (together): "<<tmh.getDif()<<std::endl;
if ( checksum )
{
tlog0 < < " \t Server checksum for " < < si - > mapname < < " : " < < checksum < < std : : endl ;
tlog0 < < " \t Our checksum for the map: " < < map - > checksum < < std : : endl ;
if ( map - > checksum ! = checksum )
{
tlog1 < < " Wrong map checksum!!! " < < std : : endl ;
throw std : : string ( " Wrong checksum " ) ;
}
}
2008-07-26 16:57:32 +03:00
day = 0 ;
2008-07-25 20:28:28 +03:00
seed = Seed ;
2008-08-04 18:56:36 +03:00
ran . seed ( ( boost : : int32_t ) seed ) ;
2008-06-30 03:06:41 +03:00
scenarioOps = si ;
2008-11-28 03:36:34 +02:00
loadTownDInfos ( ) ;
2010-02-10 04:56:00 +02:00
//pick grail location
if ( map - > grailPos . x < 0 | | map - > grailRadious ) //grail not set or set within a radius around some place
{
if ( ! map - > grailRadious ) //radius not given -> anywhere on map
map - > grailRadious = map - > width * 2 ;
std : : vector < int3 > allowedPos ;
// add all not blocked tiles in range
for ( int i = 0 ; i < map - > width ; i + + )
{
for ( int j = 0 ; j < map - > height ; j + + )
{
for ( int k = 0 ; k < = map - > twoLevel ; k + + )
{
const TerrainTile & t = map - > terrain [ i ] [ j ] [ k ] ;
if ( ! t . blocked
& & ! t . visitable
& & t . tertype ! = TerrainTile : : water
& & t . tertype ! = TerrainTile : : rock
& & map - > grailPos . dist2d ( int3 ( i , j , k ) ) < = map - > grailRadious )
allowedPos . push_back ( int3 ( i , j , k ) ) ;
}
}
}
//remove tiles with holes
for ( unsigned int no = 0 ; no < map - > objects . size ( ) ; + + no )
if ( map - > objects [ no ] - > ID = = 124 )
allowedPos - = map - > objects [ no ] - > pos ;
if ( allowedPos . size ( ) )
map - > grailPos = allowedPos [ ran ( ) % allowedPos . size ( ) ] ;
else
tlog2 < < " Warning: Grail cannot be placed, no appropriate tile found! \n " ;
}
2008-06-30 03:06:41 +03:00
//picking random factions for players
2009-05-07 08:01:45 +03:00
for ( unsigned int i = 0 ; i < scenarioOps - > playerInfos . size ( ) ; i + + )
2008-06-30 03:06:41 +03:00
{
if ( scenarioOps - > playerInfos [ i ] . castle = = - 1 )
{
int f ;
do
{
f = ran ( ) % F_NUMBER ;
} while ( ! ( map - > players [ scenarioOps - > playerInfos [ i ] . color ] . allowedFactions & 1 < < f ) ) ;
scenarioOps - > playerInfos [ i ] . castle = f ;
}
}
2010-02-10 04:56:00 +02:00
2008-06-30 03:06:41 +03:00
//randomizing objects
2010-07-09 07:29:11 +03:00
BOOST_FOREACH ( CGObjectInstance * obj , map - > objects )
2008-06-30 03:06:41 +03:00
{
2010-07-09 07:29:11 +03:00
randomizeObject ( obj ) ;
if ( obj - > ID = = EVENTI_TYPE )
2008-09-20 21:30:37 +03:00
{
2010-07-09 07:29:11 +03:00
obj - > defInfo - > handler = NULL ;
2008-09-20 21:30:37 +03:00
}
2010-07-09 07:29:11 +03:00
obj - > hoverName = VLC - > generaltexth - > names [ obj - > ID ] ;
//handle Favouring Winds - mark tiles under it
if ( obj - > ID = = 225 )
for ( int i = 0 ; i < obj - > getWidth ( ) ; i + + )
for ( int j = 0 ; j < obj - > getHeight ( ) ; j + + )
{
int3 pos = obj - > pos - int3 ( i , j , 0 ) ;
if ( map - > isInTheMap ( pos ) )
map - > getTile ( pos ) . siodmyTajemniczyBajt | = 128 ;
}
2008-06-30 03:06:41 +03:00
}
//std::cout<<"\tRandomizing objects: "<<th.getDif()<<std::endl;
2008-08-27 13:19:18 +03:00
/*********give starting hero****************************************/
2008-07-27 20:07:37 +03:00
for ( int i = 0 ; i < PLAYER_LIMIT ; i + + )
{
2009-05-07 20:20:41 +03:00
if ( ( map - > players [ i ] . generateHeroAtMainTown & & map - > players [ i ] . hasMainTown ) | | ( map - > players [ i ] . hasMainTown & & map - > version = = CMapHeader : : RoE ) )
2008-07-27 20:07:37 +03:00
{
int3 hpos = map - > players [ i ] . posOfMainTown ;
hpos . x + = 1 ; // hpos.y+=1;
int j ;
2009-05-07 18:19:52 +03:00
for ( j = 0 ; j < scenarioOps - > playerInfos . size ( ) ; j + + ) //don't add unsigned here - we are refering to the variable above
2008-07-27 20:07:37 +03:00
if ( scenarioOps - > playerInfos [ j ] . color = = i )
break ;
if ( j = = scenarioOps - > playerInfos . size ( ) )
continue ;
2009-08-27 11:04:32 +03:00
2008-07-27 20:07:37 +03:00
int h = pickHero ( i ) ;
2009-08-27 11:04:32 +03:00
if ( scenarioOps - > playerInfos [ j ] . hero = = - 1 )
scenarioOps - > playerInfos [ j ] . hero = h ;
2009-02-06 16:15:45 +02:00
CGHeroInstance * nnn = static_cast < CGHeroInstance * > ( createObject ( HEROI_TYPE , h , hpos , i ) ) ;
2008-07-27 20:07:37 +03:00
nnn - > id = map - > objects . size ( ) ;
2008-08-13 12:28:06 +03:00
hpos = map - > players [ i ] . posOfMainTown ; hpos . x + = 2 ;
2009-05-07 08:01:45 +03:00
for ( unsigned int o = 0 ; o < map - > towns . size ( ) ; o + + ) //find main town
2008-08-13 12:28:06 +03:00
{
if ( map - > towns [ o ] - > pos = = hpos )
{
map - > towns [ o ] - > visitingHero = nnn ;
nnn - > visitedTown = map - > towns [ o ] ;
nnn - > inTownGarrison = false ;
break ;
}
}
2008-10-26 22:58:34 +02:00
nnn - > initHero ( ) ;
2008-07-27 20:07:37 +03:00
map - > heroes . push_back ( nnn ) ;
map - > objects . push_back ( nnn ) ;
2008-09-17 13:18:22 +03:00
map - > addBlockVisTiles ( nnn ) ;
2008-07-27 20:07:37 +03:00
}
}
2008-06-30 03:06:41 +03:00
/*********creating players entries in gs****************************************/
2009-05-07 08:01:45 +03:00
for ( unsigned int i = 0 ; i < scenarioOps - > playerInfos . size ( ) ; i + + )
2008-06-30 03:06:41 +03:00
{
std : : pair < int , PlayerState > ins ( scenarioOps - > playerInfos [ i ] . color , PlayerState ( ) ) ;
ins . second . color = ins . first ;
ins . second . serial = i ;
2009-03-09 21:40:43 +02:00
ins . second . human = scenarioOps - > playerInfos [ i ] . human ;
2008-06-30 03:06:41 +03:00
players . insert ( ins ) ;
}
/******************RESOURCES****************************************************/
2009-12-02 01:19:43 +02:00
//TODO: computer player should receive other amount of resource than player (depending on difficulty)
2008-06-30 03:06:41 +03:00
std : : vector < int > startres ;
2009-10-04 05:02:45 +03:00
std : : ifstream tis ( DATA_DIR " /config/startres.txt " ) ;
2008-06-30 03:06:41 +03:00
int k ;
for ( int j = 0 ; j < scenarioOps - > difficulty ; j + + )
{
tis > > k ;
for ( int z = 0 ; z < RESOURCE_QUANTITY ; z + + )
tis > > k ;
}
tis > > k ;
for ( int i = 0 ; i < RESOURCE_QUANTITY ; i + + )
{
tis > > k ;
startres . push_back ( k ) ;
}
tis . close ( ) ;
2008-09-07 06:38:37 +03:00
tis . clear ( ) ;
2008-07-25 20:28:28 +03:00
for ( std : : map < ui8 , PlayerState > : : iterator i = players . begin ( ) ; i ! = players . end ( ) ; i + + )
2008-06-30 03:06:41 +03:00
{
( * i ) . second . resources . resize ( RESOURCE_QUANTITY ) ;
for ( int x = 0 ; x < RESOURCE_QUANTITY ; x + + )
( * i ) . second . resources [ x ] = startres [ x ] ;
}
2008-09-07 06:38:37 +03:00
2008-06-30 03:06:41 +03:00
/*************************HEROES************************************************/
2010-07-08 08:52:11 +03:00
std : : set < int > hids ; //hero ids to create pool
2009-05-07 08:01:45 +03:00
for ( unsigned int i = 0 ; i < map - > allowedHeroes . size ( ) ; i + + ) //add to hids all allowed heroes
2008-10-26 22:58:34 +02:00
if ( map - > allowedHeroes [ i ] )
hids . insert ( i ) ;
2010-07-08 08:52:11 +03:00
2009-05-07 08:01:45 +03:00
for ( unsigned int i = 0 ; i < map - > heroes . size ( ) ; i + + ) //heroes instances initialization
2008-06-30 03:06:41 +03:00
{
if ( map - > heroes [ i ] - > getOwner ( ) < 0 )
{
2008-10-26 22:58:34 +02:00
tlog2 < < " Warning - hero with uninitialized owner! \n " ;
continue ;
2008-06-30 03:06:41 +03:00
}
2008-10-26 22:58:34 +02:00
CGHeroInstance * vhi = ( map - > heroes [ i ] ) ;
vhi - > initHero ( ) ;
2008-12-22 19:48:41 +02:00
players . find ( vhi - > getOwner ( ) ) - > second . heroes . push_back ( vhi ) ;
2008-10-26 22:58:34 +02:00
hids . erase ( vhi - > subID ) ;
}
2010-07-08 08:52:11 +03:00
for ( unsigned int i = 0 ; i < map - > objects . size ( ) ; i + + ) //prisons
2010-02-10 23:31:54 +02:00
{
if ( map - > objects [ i ] - > ID = = 62 )
hids . erase ( map - > objects [ i ] - > subID ) ;
}
2010-07-08 08:52:11 +03:00
2009-05-07 08:01:45 +03:00
for ( unsigned int i = 0 ; i < map - > predefinedHeroes . size ( ) ; i + + )
2008-10-26 22:58:34 +02:00
{
if ( ! vstd : : contains ( hids , map - > predefinedHeroes [ i ] - > subID ) )
continue ;
map - > predefinedHeroes [ i ] - > initHero ( ) ;
hpool . heroesPool [ map - > predefinedHeroes [ i ] - > subID ] = map - > predefinedHeroes [ i ] ;
hpool . pavailable [ map - > predefinedHeroes [ i ] - > subID ] = 0xff ;
hids . erase ( map - > predefinedHeroes [ i ] - > subID ) ;
}
2010-07-08 08:52:11 +03:00
BOOST_FOREACH ( int hid , hids ) //all not used allowed heroes go with default state into the pool
2008-10-26 22:58:34 +02:00
{
CGHeroInstance * vhi = new CGHeroInstance ( ) ;
vhi - > initHero ( hid ) ;
hpool . heroesPool [ hid ] = vhi ;
hpool . pavailable [ hid ] = 0xff ;
}
2010-07-08 08:52:11 +03:00
2009-05-07 08:01:45 +03:00
for ( unsigned int i = 0 ; i < map - > disposedHeroes . size ( ) ; i + + )
2008-10-26 22:58:34 +02:00
{
hpool . pavailable [ map - > disposedHeroes [ i ] . ID ] = map - > disposedHeroes [ i ] . players ;
2008-06-30 03:06:41 +03:00
}
2010-07-08 08:52:11 +03:00
2008-06-30 03:06:41 +03:00
/*************************FOG**OF**WAR******************************************/
2008-07-25 20:28:28 +03:00
for ( std : : map < ui8 , PlayerState > : : iterator k = players . begin ( ) ; k ! = players . end ( ) ; + + k )
2008-06-30 03:06:41 +03:00
{
k - > second . fogOfWarMap . resize ( map - > width ) ;
for ( int g = 0 ; g < map - > width ; + + g )
k - > second . fogOfWarMap [ g ] . resize ( map - > height ) ;
for ( int g = - 0 ; g < map - > width ; + + g )
for ( int h = 0 ; h < map - > height ; + + h )
k - > second . fogOfWarMap [ g ] [ h ] . resize ( map - > twoLevel + 1 , 0 ) ;
for ( int g = 0 ; g < map - > width ; + + g )
for ( int h = 0 ; h < map - > height ; + + h )
for ( int v = 0 ; v < map - > twoLevel + 1 ; + + v )
k - > second . fogOfWarMap [ g ] [ h ] [ v ] = 0 ;
2009-03-12 01:25:59 +02:00
BOOST_FOREACH ( CGObjectInstance * obj , map - > objects )
2008-06-30 03:06:41 +03:00
{
2009-03-12 01:25:59 +02:00
if ( obj - > tempOwner ! = k - > first ) continue ; //not a flagged object
2009-11-11 19:45:03 +02:00
std : : set < int3 > tiles ;
obj - > getSightTiles ( tiles ) ;
BOOST_FOREACH ( int3 tile , tiles )
{
k - > second . fogOfWarMap [ tile . x ] [ tile . y ] [ tile . z ] = 1 ;
}
2008-06-30 03:06:41 +03:00
}
2008-08-26 00:14:00 +03:00
//starting bonus
if ( si - > playerInfos [ k - > second . serial ] . bonus = = brandom )
si - > playerInfos [ k - > second . serial ] . bonus = ran ( ) % 3 ;
switch ( si - > playerInfos [ k - > second . serial ] . bonus )
{
case bgold :
k - > second . resources [ 6 ] + = 500 + ( ran ( ) % 6 ) * 100 ;
break ;
case bresource :
{
int res = VLC - > townh - > towns [ si - > playerInfos [ k - > second . serial ] . castle ] . primaryRes ;
if ( res = = 127 )
{
k - > second . resources [ 0 ] + = 5 + ran ( ) % 6 ;
k - > second . resources [ 2 ] + = 5 + ran ( ) % 6 ;
}
else
{
k - > second . resources [ res ] + = 3 + ran ( ) % 4 ;
}
break ;
}
case bartifact :
{
2010-07-06 08:09:06 +03:00
if ( ! k - > second . heroes . size ( ) )
{
tlog5 < < " Cannot give starting artifact - no heroes! " < < std : : endl ;
break ;
}
CArtifact * toGive ;
toGive = VLC - > arth - > artifacts [ VLC - > arth - > getRandomArt ( CArtifact : : ART_TREASURE ) ] ;
CGHeroInstance * hero = k - > second . heroes [ 0 ] ;
std : : vector < ui16 > : : iterator slot = vstd : : findFirstNot ( hero - > artifWorn , toGive - > possibleSlots ) ;
2010-07-20 21:34:32 +03:00
if ( slot ! = toGive - > possibleSlots . end ( ) )
VLC - > arth - > equipArtifact ( hero - > artifWorn , * slot , toGive - > id ) ;
2010-07-06 08:09:06 +03:00
else
hero - > giveArtifact ( toGive - > id ) ;
2008-08-26 00:14:00 +03:00
}
}
2008-06-30 03:06:41 +03:00
}
/****************************TOWNS************************************************/
2010-07-20 17:08:13 +03:00
for ( int i = 0 ; i < 4 ; i + + )
CGTownInstance : : universitySkills . push_back ( 14 + i ) ; //skills for university
2009-05-07 08:01:45 +03:00
for ( unsigned int i = 0 ; i < map - > towns . size ( ) ; i + + )
2008-06-30 03:06:41 +03:00
{
CGTownInstance * vti = ( map - > towns [ i ] ) ;
if ( ! vti - > town )
vti - > town = & VLC - > townh - > towns [ vti - > subID ] ;
if ( vti - > name . length ( ) = = 0 ) // if town hasn't name we draw it
2008-12-22 19:48:41 +02:00
vti - > name = vti - > town - > Names ( ) [ ran ( ) % vti - > town - > Names ( ) . size ( ) ] ;
2008-08-20 09:57:53 +03:00
//init buildings
2008-06-30 03:06:41 +03:00
if ( vti - > builtBuildings . find ( - 50 ) ! = vti - > builtBuildings . end ( ) ) //give standard set of buildings
{
vti - > builtBuildings . erase ( - 50 ) ;
vti - > builtBuildings . insert ( 10 ) ;
vti - > builtBuildings . insert ( 5 ) ;
vti - > builtBuildings . insert ( 30 ) ;
if ( ran ( ) % 2 )
vti - > builtBuildings . insert ( 31 ) ;
2010-06-30 22:27:35 +03:00
}
2010-07-20 17:08:13 +03:00
if ( vstd : : contains ( vti - > builtBuildings , ( 6 ) ) & & vti - > state ( ) = = 2 )
2010-06-30 22:27:35 +03:00
vti - > builtBuildings . erase ( 6 ) ; //if we have harbor without water - erase it (this is H3 behaviour)
//init hordes
2010-02-13 17:56:34 +02:00
for ( int i = 0 ; i < CREATURES_PER_TOWN ; i + + )
if ( vstd : : contains ( vti - > builtBuildings , ( - 31 - i ) ) ) //if we have horde for this level
{
vti - > builtBuildings . erase ( - 31 - i ) ; //remove old ID
if ( vti - > town - > hordeLvl [ 0 ] = = i ) //if town first horde is this one
{
vti - > builtBuildings . insert ( 18 ) ; //add it
if ( vstd : : contains ( vti - > builtBuildings , ( 37 + i ) ) ) //if we have upgraded dwelling as well
vti - > builtBuildings . insert ( 19 ) ; //add it as well
}
if ( vti - > town - > hordeLvl [ 1 ] = = i ) //if town second horde is this one
{
vti - > builtBuildings . insert ( 24 ) ;
if ( vstd : : contains ( vti - > builtBuildings , ( 37 + i ) ) )
vti - > builtBuildings . insert ( 25 ) ;
}
}
2008-08-20 09:57:53 +03:00
//init spells
vti - > spells . resize ( SPELL_LEVELS ) ;
CSpell * s ;
2009-05-07 08:01:45 +03:00
for ( unsigned int z = 0 ; z < vti - > obligatorySpells . size ( ) ; z + + )
2008-08-20 09:57:53 +03:00
{
s = & VLC - > spellh - > spells [ vti - > obligatorySpells [ z ] ] ;
vti - > spells [ s - > level - 1 ] . push_back ( s - > id ) ;
vti - > possibleSpells - = s - > id ;
}
while ( vti - > possibleSpells . size ( ) )
{
ui32 total = 0 , sel = - 1 ;
2009-05-07 08:01:45 +03:00
for ( unsigned int ps = 0 ; ps < vti - > possibleSpells . size ( ) ; ps + + )
2008-08-20 09:57:53 +03:00
total + = VLC - > spellh - > spells [ vti - > possibleSpells [ ps ] ] . probabilities [ vti - > subID ] ;
int r = ( total ) ? ran ( ) % total : - 1 ;
2009-05-07 08:01:45 +03:00
for ( unsigned int ps = 0 ; ps < vti - > possibleSpells . size ( ) ; ps + + )
2008-08-20 09:57:53 +03:00
{
r - = VLC - > spellh - > spells [ vti - > possibleSpells [ ps ] ] . probabilities [ vti - > subID ] ;
if ( r < 0 )
{
sel = ps ;
break ;
}
}
if ( sel < 0 )
sel = 0 ;
CSpell * s = & VLC - > spellh - > spells [ vti - > possibleSpells [ sel ] ] ;
vti - > spells [ s - > level - 1 ] . push_back ( s - > id ) ;
vti - > possibleSpells - = s - > id ;
}
2009-03-09 12:37:49 +02:00
if ( vti - > getOwner ( ) ! = 255 )
getPlayer ( vti - > getOwner ( ) ) - > towns . push_back ( vti ) ;
2008-06-30 03:06:41 +03:00
}
2008-07-25 20:28:28 +03:00
for ( std : : map < ui8 , PlayerState > : : iterator k = players . begin ( ) ; k ! = players . end ( ) ; + + k )
2008-06-30 03:06:41 +03:00
{
if ( k - > first = = - 1 | | k - > first = = 255 )
continue ;
2008-08-20 09:57:53 +03:00
//init visiting and garrisoned heroes
2009-04-13 21:52:20 +03:00
for ( unsigned int l = 0 ; l < k - > second . heroes . size ( ) ; l + + )
2008-06-30 03:06:41 +03:00
{
2009-09-13 01:17:23 +03:00
CGHeroInstance * h = k - > second . heroes [ l ] ;
2009-04-13 21:52:20 +03:00
for ( unsigned int m = 0 ; m < k - > second . towns . size ( ) ; m + + )
2008-06-30 03:06:41 +03:00
{
2009-09-13 01:17:23 +03:00
CGTownInstance * t = k - > second . towns [ m ] ;
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
{
2009-09-13 01:17:23 +03:00
t - > visitingHero = h ;
h - > visitedTown = t ;
h - > inTownGarrison = false ;
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
}
}
}
}
2008-12-27 03:01:59 +02:00
2009-05-07 08:01:45 +03:00
for ( unsigned int i = 0 ; i < map - > defy . size ( ) ; i + + )
2009-01-06 20:42:20 +02:00
{
map - > defy [ i ] - > serial = i ;
}
2009-09-07 05:29:44 +03:00
objCaller - > preInit ( ) ;
2009-05-07 08:01:45 +03:00
for ( unsigned int i = 0 ; i < map - > objects . size ( ) ; i + + )
2009-02-14 21:12:40 +02:00
{
2008-12-27 03:01:59 +02:00
map - > objects [ i ] - > initObj ( ) ;
2009-02-14 21:12:40 +02:00
if ( map - > objects [ i ] - > ID = = 62 ) //prison also needs to initialize hero
static_cast < CGHeroInstance * > ( map - > objects [ i ] ) - > initHero ( ) ;
}
2009-09-07 05:29:44 +03:00
objCaller - > postInit ( ) ;
2008-06-30 03:06:41 +03:00
}
2008-05-27 16:16:35 +03:00
2008-08-02 18:08:03 +03:00
bool CGameState : : battleShootCreatureStack ( int ID , int dest )
2008-08-09 02:02:32 +03:00
{
2008-08-02 18:08:03 +03:00
return true ;
}
2009-08-16 16:44:17 +03:00
bool CGameState : : battleCanFlee ( int player )
{
if ( ! curB ) //there is no battle
return false ;
2010-05-02 21:20:26 +03:00
if ( curB - > heroes [ 0 ] - > hasBonusOfType ( Bonus : : ENEMY_CANT_ESCAPE ) //eg. one of heroes is wearing shakles of war
| | curB - > heroes [ 0 ] - > hasBonusOfType ( Bonus : : ENEMY_CANT_ESCAPE ) )
2009-08-16 16:44:17 +03:00
return false ;
return true ;
}
2009-08-05 15:46:08 +03:00
int CGameState : : battleGetStack ( int pos , bool onlyAlive )
2008-08-02 18:08:03 +03:00
{
2008-09-05 19:08:25 +03:00
if ( ! curB )
return - 1 ;
2009-05-07 08:01:45 +03:00
for ( unsigned int g = 0 ; g < curB - > stacks . size ( ) ; + + g )
2008-08-02 18:08:03 +03:00
{
2008-11-30 02:15:38 +02:00
if ( ( curB - > stacks [ g ] - > position = = pos
2010-05-02 21:20:26 +03:00
| | ( curB - > stacks [ g ] - > doubleWide ( )
2008-11-30 02:15:38 +02:00
& & ( ( curB - > stacks [ g ] - > attackerOwned & & curB - > stacks [ g ] - > position - 1 = = pos )
| | ( ! curB - > stacks [ g ] - > attackerOwned & & curB - > stacks [ g ] - > position + 1 = = pos ) )
) )
2009-08-05 15:46:08 +03:00
& & ( ! onlyAlive | | curB - > stacks [ g ] - > alive ( ) )
2008-11-30 02:15:38 +02:00
)
2008-08-02 18:08:03 +03:00
return curB - > stacks [ g ] - > ID ;
}
return - 1 ;
}
2009-02-09 16:50:32 +02:00
int CGameState : : battleGetBattlefieldType ( int3 tile )
{
2009-02-10 16:21:51 +02:00
if ( tile = = int3 ( ) & & curB )
tile = curB - > tile ;
else if ( tile = = int3 ( ) & & ! curB )
2009-02-09 16:50:32 +02:00
return - 1 ;
2009-02-10 16:21:51 +02:00
2009-07-06 22:41:27 +03:00
const std : : vector < CGObjectInstance * > & objs = map - > objects ;
2009-07-01 18:58:20 +03:00
for ( int g = 0 ; g < objs . size ( ) ; + + g )
{
2009-07-06 22:41:27 +03:00
if ( ! objs [ g ] | | objs [ g ] - > pos . x - tile . x < 0 | | objs [ g ] - > pos . x - tile . x > = 8
| | tile . y - objs [ g ] - > pos . y + 5 < 0 | | tile . y - objs [ g ] - > pos . y + 5 > = 6
| | ! objs [ g ] - > coveringAt ( objs [ g ] - > pos . x - tile . x , tile . y - objs [ g ] - > pos . y + 5 )
2009-07-01 18:58:20 +03:00
) //look only for objects covering given tile
continue ;
switch ( objs [ g ] - > ID )
{
case 222 : //clover field
return 19 ;
2009-07-22 12:31:20 +03:00
case 21 : case 223 : //cursed ground
2009-07-01 18:58:20 +03:00
return 22 ;
case 224 : //evil fog
return 20 ;
case 225 : //favourable winds
return 21 ;
case 226 : //fiery fields
return 14 ;
case 227 : //holy ground
return 18 ;
case 228 : //lucid pools
return 17 ;
case 229 : //magic clouds
return 16 ;
2009-07-22 12:31:20 +03:00
case 46 : case 230 : //magic plains
2009-07-01 18:58:20 +03:00
return 9 ;
case 231 : //rocklands
return 15 ;
}
}
2009-02-14 15:49:30 +02:00
2009-02-10 16:21:51 +02:00
switch ( map - > terrain [ tile . x ] [ tile . y ] [ tile . z ] . tertype )
{
2009-05-07 20:20:41 +03:00
case TerrainTile : : dirt :
2009-02-10 16:21:51 +02:00
return rand ( ) % 3 + 3 ;
2009-05-07 20:20:41 +03:00
case TerrainTile : : sand :
2009-02-10 16:21:51 +02:00
return 2 ; //TODO: coast support
2009-05-07 20:20:41 +03:00
case TerrainTile : : grass :
2009-02-10 16:21:51 +02:00
return rand ( ) % 2 + 6 ;
2009-05-07 20:20:41 +03:00
case TerrainTile : : snow :
2009-02-10 16:21:51 +02:00
return rand ( ) % 2 + 10 ;
2009-05-07 20:20:41 +03:00
case TerrainTile : : swamp :
2009-02-10 16:21:51 +02:00
return 13 ;
2009-05-07 20:20:41 +03:00
case TerrainTile : : rough :
2009-02-10 16:21:51 +02:00
return 23 ;
2009-05-07 20:20:41 +03:00
case TerrainTile : : subterranean :
2009-02-10 16:21:51 +02:00
return 12 ;
2009-05-07 20:20:41 +03:00
case TerrainTile : : lava :
2009-02-10 16:21:51 +02:00
return 8 ;
2009-05-07 20:20:41 +03:00
case TerrainTile : : water :
2009-02-10 16:21:51 +02:00
return 25 ;
2009-05-07 20:20:41 +03:00
case TerrainTile : : rock :
2009-02-10 16:21:51 +02:00
return 15 ;
default :
return - 1 ;
}
2009-02-09 16:50:32 +02:00
}
2009-09-05 17:10:26 +03:00
const CGHeroInstance * CGameState : : battleGetOwner ( int stackID )
{
if ( ! curB )
return NULL ;
2009-10-06 03:32:33 +03:00
return curB - > heroes [ ! curB - > getStack ( stackID ) - > attackerOwned ] ;
2009-09-05 17:10:26 +03:00
}
2010-07-15 06:04:57 +03:00
std : : set < std : : pair < int , int > > costDiff ( const std : : vector < ui32 > & a , const std : : vector < ui32 > & b , const int modifier = 100 ) //modifer %
{
std : : set < std : : pair < int , int > > ret ;
for ( int j = 0 ; j < RESOURCE_QUANTITY ; j + + )
{
assert ( a [ j ] > = b [ j ] ) ;
if ( int dif = modifier * ( a [ j ] - b [ j ] ) / 100 )
ret . insert ( std : : make_pair ( j , dif ) ) ;
}
return ret ;
}
UpgradeInfo CGameState : : getUpgradeInfo ( const CStackInstance & stack )
2008-08-15 15:11:42 +03:00
{
UpgradeInfo ret ;
2010-07-15 06:04:57 +03:00
const CCreature * base = stack . type ;
const CGHeroInstance * h = stack . armyObj - > ID = = HEROI_TYPE ? static_cast < const CGHeroInstance * > ( stack . armyObj ) : NULL ;
const CGTownInstance * t = NULL ;
if ( stack . armyObj - > ID = = TOWNI_TYPE )
t = static_cast < const CGTownInstance * > ( stack . armyObj ) ;
else if ( h )
2010-07-17 09:49:16 +03:00
{ //TODO: check if hero specialty makes some upgrades possible
BonusList lista = h - > speciality . getBonuses ( Selector : : typeSybtype ( Bonus : : SPECIAL_UPGRADE , base - > idNumber ) ) ;
for ( BonusList : : iterator it = lista . begin ( ) ; it ! = lista . end ( ) ; it + + )
{
ui16 nid = it - > additionalInfo ;
if ( nid ! = base - > idNumber ) //sharpshooter appears to be default upgrade of minor creatures (?)
{
ret . newID . push_back ( nid ) ;
ret . cost . push_back ( costDiff ( VLC - > creh - > creatures [ nid ] - > cost , base - > cost ) ) ;
}
}
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
{
2010-07-15 06:04:57 +03:00
BOOST_FOREACH ( si32 bid , t - > builtBuildings )
2008-08-15 15:11:42 +03:00
{
2010-07-15 06:04:57 +03:00
if ( bid > = 37 & & bid < 44 ) //upgraded creature dwelling
2008-08-15 15:11:42 +03:00
{
2010-07-15 06:04:57 +03:00
int nid = t - > town - > upgradedCreatures [ bid - 37 ] ; //upgrade offered by that building
if ( vstd : : contains ( base - > upgrades , nid ) ) //possible upgrade
2008-08-15 15:11:42 +03:00
{
ret . newID . push_back ( nid ) ;
2010-07-15 06:04:57 +03:00
ret . cost . push_back ( costDiff ( VLC - > creh - > creatures [ nid ] - > cost , base - > cost ) ) ;
2008-08-15 15:11:42 +03:00
}
}
2010-07-15 06:04:57 +03:00
}
}
//hero is visiting Hill Fort
if ( h & & map - > getTile ( h - > visitablePos ( ) ) . visitableObjects . front ( ) - > ID = = 35 )
{
static const int costModifiers [ ] = { 0 , 25 , 50 , 75 , 100 } ; //we get cheaper upgrades depending on level
const int costModifier = costModifiers [ std : : min < int > ( std : : max ( ( int ) base - > level - 1 , 0 ) , ARRAY_COUNT ( costModifiers ) - 1 ) ] ;
BOOST_FOREACH ( si32 nid , base - > upgrades )
{
ret . newID . push_back ( nid ) ;
ret . cost . push_back ( costDiff ( VLC - > creh - > creatures [ nid ] - > cost , base - > cost , costModifier ) ) ;
}
2008-08-15 15:11:42 +03:00
}
2010-07-15 06:04:57 +03:00
2008-08-15 15:11:42 +03:00
if ( ret . newID . size ( ) )
ret . oldID = base - > idNumber ;
return ret ;
}
2008-09-07 06:38:37 +03:00
2008-11-28 03:36:34 +02:00
void CGameState : : loadTownDInfos ( )
{
for ( int i = 0 ; i < F_NUMBER ; i + + )
{
villages [ i ] = new CGDefInfo ( * VLC - > dobjinfo - > castles [ i ] ) ;
forts [ i ] = VLC - > dobjinfo - > castles [ i ] ;
capitols [ i ] = new CGDefInfo ( * VLC - > dobjinfo - > castles [ i ] ) ;
}
}
2008-12-27 03:01:59 +02:00
2010-07-10 05:15:49 +03:00
void CGameState : : getNeighbours ( const TerrainTile & srct , int3 tile , std : : vector < int3 > & vec , const boost : : logic : : tribool & onLand , bool limitCoastSailing )
2009-02-12 16:44:58 +02:00
{
2009-08-22 16:59:15 +03:00
static 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 ) } ;
2009-02-12 16:44:58 +02:00
vec . clear ( ) ;
2009-07-19 04:00:19 +03:00
for ( size_t i = 0 ; i < ARRAY_COUNT ( dirs ) ; i + + )
2009-02-12 16:44:58 +02:00
{
2009-08-30 15:47:40 +03:00
const int3 hlp = tile + dirs [ i ] ;
2009-07-19 04:00:19 +03:00
if ( ! map - > isInTheMap ( hlp ) )
continue ;
2009-08-30 15:47:40 +03:00
const TerrainTile & hlpt = map - > getTile ( hlp ) ;
2010-05-16 16:42:19 +03:00
//we cannot visit things from blocked tiles
2010-05-27 00:59:58 +03:00
if ( srct . blocked & & ! srct . visitable & & hlpt . visitable & & srct . blockingObjects . front ( ) - > ID ! = HEROI_TYPE )
2010-05-16 16:42:19 +03:00
{
continue ;
}
2010-07-10 05:15:49 +03:00
if ( srct . tertype = = TerrainTile : : water & & limitCoastSailing & & hlpt . tertype = = TerrainTile : : water & & dirs [ i ] . x & & dirs [ i ] . y ) //diagonal move through water
{
int3 hlp1 = tile ,
hlp2 = tile ;
hlp1 . x + = dirs [ i ] . x ;
hlp2 . y + = dirs [ i ] . y ;
if ( map - > getTile ( hlp1 ) . tertype ! = TerrainTile : : water | | map - > getTile ( hlp2 ) . tertype ! = TerrainTile : : water )
continue ;
}
2010-05-15 18:00:19 +03:00
if ( ( indeterminate ( onLand ) | | onLand = = ( hlpt . tertype ! = TerrainTile : : water ) )
& & hlpt . tertype ! = TerrainTile : : rock )
2009-07-19 04:00:19 +03:00
{
2009-02-12 16:44:58 +02:00
vec . push_back ( hlp ) ;
2009-07-19 04:00:19 +03:00
}
2009-02-12 16:44:58 +02:00
}
}
2009-08-30 15:47:40 +03:00
int CGameState : : getMovementCost ( const CGHeroInstance * h , const int3 & src , const int3 & dest , int remainingMovePoints , bool checkLast )
2009-02-12 16:44:58 +02:00
{
2009-03-27 01:05:40 +02:00
if ( src = = dest ) //same tile
return 0 ;
2009-02-12 16:44:58 +02:00
TerrainTile & s = map - > terrain [ src . x ] [ src . y ] [ src . z ] ,
& d = map - > terrain [ dest . x ] [ dest . y ] [ dest . z ] ;
//get basic cost
int ret = h - > getTileCost ( d , s ) ;
2010-05-31 23:38:14 +03:00
if ( d . blocked & & h - > hasBonusOfType ( Bonus : : FLYING_MOVEMENT ) )
2010-05-15 18:00:19 +03:00
{
bool freeFlying = h - > getBonusesCount ( Selector : : typeSybtype ( Bonus : : FLYING_MOVEMENT , 1 ) ) > 0 ;
if ( ! freeFlying )
{
ret * = 1.4f ; //40% penalty for movement over blocked tile
}
}
else if ( d . tertype = = TerrainTile : : water )
{
2010-07-09 07:29:11 +03:00
if ( h - > boat & & s . siodmyTajemniczyBajt & 128 & & d . siodmyTajemniczyBajt & 128 ) //Favourable Winds
ret * = 0.666f ;
else if ( ! h - > boat & & h - > getBonusesCount ( Selector : : typeSybtype ( Bonus : : WATER_WALKING , 1 ) ) > 0 )
2010-05-15 18:00:19 +03:00
ret * = 1.4f ; //40% penalty for water walking
}
2009-08-28 12:03:58 +03:00
if ( src . x ! = dest . x & & src . y ! = dest . y ) //it's diagonal move
2009-02-12 16:44:58 +02:00
{
int old = ret ;
2009-08-28 12:03:58 +03:00
ret * = 1.414213 ;
2009-07-19 04:00:19 +03:00
//diagonal move costs too much but normal move is possible - allow diagonal move for remaining move points
2009-08-30 15:47:40 +03:00
if ( ret > remainingMovePoints & & remainingMovePoints > = old )
2009-02-12 16:44:58 +02:00
{
return remainingMovePoints ;
}
}
int left = remainingMovePoints - ret ;
if ( checkLast & & left > 0 & & remainingMovePoints - ret < 250 ) //it might be the last tile - if no further move possible we take all move points
{
std : : vector < int3 > vec ;
2010-07-10 05:15:49 +03:00
getNeighbours ( d , dest , vec , s . tertype ! = TerrainTile : : water , true ) ;
2009-02-12 16:44:58 +02:00
for ( size_t i = 0 ; i < vec . size ( ) ; i + + )
{
int fcost = getMovementCost ( h , dest , vec [ i ] , left , false ) ;
if ( fcost < = left )
{
return ret ;
}
}
ret = remainingMovePoints ;
}
return ret ;
}
2009-12-30 09:49:25 +02:00
std : : set < int > CGameState : : getBuildingRequiments ( const CGTownInstance * t , int ID )
{
2009-12-29 15:40:16 +02:00
std : : set < int > used ;
2009-12-30 09:49:25 +02:00
used . insert ( ID ) ;
2009-12-29 15:40:16 +02:00
std : : set < int > reqs = VLC - > townh - > requirements [ t - > subID ] [ ID ] ;
2009-12-30 09:49:25 +02:00
2009-12-29 15:40:16 +02:00
while ( true )
{
size_t noloop = 0 ;
for ( std : : set < int > : : iterator i = reqs . begin ( ) ; i ! = reqs . end ( ) ; i + + )
{
if ( used . find ( * i ) = = used . end ( ) ) //we haven't added requirements for this building
2009-12-30 09:49:25 +02:00
{
2009-12-29 15:40:16 +02:00
used . insert ( * i ) ;
for (
std : : set < int > : : iterator j = VLC - > townh - > requirements [ t - > subID ] [ * i ] . begin ( ) ;
j ! = VLC - > townh - > requirements [ t - > subID ] [ * i ] . end ( ) ;
j + + )
{
reqs . insert ( * j ) ; //creating full list of requirements
}
}
else
{
noloop + + ;
}
}
if ( noloop = = reqs . size ( ) )
break ;
2009-12-30 09:49:25 +02:00
}
return reqs ;
}
2009-02-12 16:44:58 +02:00
2009-02-20 17:44:49 +02:00
int CGameState : : canBuildStructure ( const CGTownInstance * t , int ID )
{
2009-12-30 09:49:25 +02:00
int ret = 7 ; //allowed by default
2009-12-29 15:40:16 +02:00
if ( t - > builded > = MAX_BUILDING_PER_TURN )
ret = 5 ; //building limit
2009-02-20 17:44:49 +02:00
//checking resources
CBuilding * pom = VLC - > buildh - > buildings [ t - > subID ] [ ID ] ;
2009-08-05 12:46:55 +03:00
2010-02-24 15:03:36 +02:00
if ( ! pom )
return 8 ;
// if(pom->Name().size()==0||pom->resources.size()==0)
// return 2;//TODO: why does this happen?
2009-08-05 12:46:55 +03:00
2009-08-04 04:00:47 +03:00
for ( int res = 0 ; res < pom - > resources . size ( ) ; res + + ) //TODO: support custom amount of resources
2009-02-20 17:44:49 +02:00
{
2009-03-09 12:37:49 +02:00
if ( pom - > resources [ res ] > getPlayer ( t - > tempOwner ) - > resources [ res ] )
2009-02-20 17:44:49 +02:00
ret = 6 ; //lack of res
}
2009-12-30 09:49:25 +02:00
//checking for requirements
std : : set < int > reqs = getBuildingRequiments ( t , ID ) ; //getting all requiments
2009-12-29 15:40:16 +02:00
for ( std : : set < int > : : iterator ri = reqs . begin ( ) ; ri ! = reqs . end ( ) ; ri + + )
2009-02-20 17:44:49 +02:00
{
if ( t - > builtBuildings . find ( * ri ) = = t - > builtBuildings . end ( ) )
ret = 8 ; //lack of requirements - cannot build
}
2009-03-28 02:38:48 +02:00
//can we build it?
if ( t - > forbiddenBuildings . find ( ID ) ! = t - > forbiddenBuildings . end ( ) )
ret = 2 ; //forbidden
2009-02-20 17:44:49 +02:00
if ( ID = = 13 ) //capitol
{
2009-05-07 08:01:45 +03:00
for ( unsigned int in = 0 ; in < map - > towns . size ( ) ; in + + )
2009-02-20 17:44:49 +02:00
{
if ( map - > towns [ in ] - > tempOwner = = t - > tempOwner & & vstd : : contains ( map - > towns [ in ] - > builtBuildings , 13 ) )
{
ret = 0 ; //no more than one capitol
break ;
}
}
}
else if ( ID = = 6 ) //shipyard
{
2009-07-12 17:07:36 +03:00
int3 t1 ( t - > pos + int3 ( - 1 , 3 , 0 ) ) ,
t2 ( t - > pos + int3 ( - 3 , 3 , 0 ) ) ;
if ( map - > isInTheMap ( t1 ) & & map - > getTile ( t1 ) . tertype ! = TerrainTile : : water
& & ( map - > isInTheMap ( t2 ) & & map - > getTile ( t2 ) . tertype ! = TerrainTile : : water ) )
2009-02-20 17:44:49 +02:00
ret = 1 ; //lack of water
}
2009-08-04 04:00:47 +03:00
if ( t - > builtBuildings . find ( ID ) ! = t - > builtBuildings . end ( ) ) //already built
ret = 4 ;
2009-02-20 17:44:49 +02:00
return ret ;
}
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 ) ;
assert ( typ > = 0 ) ;
applierGs - > apps [ typ ] - > applyOnGS ( this , pack ) ;
2009-03-07 00:25:19 +02:00
}
2010-02-10 04:56:00 +02:00
PlayerState * CGameState : : getPlayer ( ui8 color , bool verbose )
2009-03-09 12:37:49 +02:00
{
if ( vstd : : contains ( players , color ) )
{
return & players [ color ] ;
}
else
{
2010-02-10 04:56:00 +02:00
if ( verbose )
tlog2 < < " Warning: Cannot find info for player " < < int ( color ) < < std : : endl ;
2009-03-09 12:37:49 +02:00
return NULL ;
}
}
2010-02-10 04:56:00 +02:00
const PlayerState * CGameState : : getPlayer ( ui8 color , bool verbose ) const
2010-01-29 22:52:45 +02:00
{
2010-02-10 04:56:00 +02:00
return ( const_cast < CGameState * > ( this ) ) - > getPlayer ( color , verbose ) ;
2010-01-29 22:52:45 +02:00
}
2009-06-11 20:21:06 +03:00
bool CGameState : : getPath ( int3 src , int3 dest , const CGHeroInstance * hero , CPath & ret )
2009-03-19 16:17:19 +02:00
{
if ( ! map - > isInTheMap ( src ) | | ! map - > isInTheMap ( dest ) ) //check input
2009-06-11 20:21:06 +03:00
return false ;
2009-03-19 16:17:19 +02:00
int3 hpos = hero - > getPosition ( false ) ;
2010-03-21 00:17:19 +02:00
bool flying = false ; //hero is under flying effect TODO
bool waterWalking = false ; //hero is on land and can walk on water TODO
bool onLand = map - > getTile ( hpos ) . tertype ! = TerrainTile : : water ;
// tribool blockLandSea; //true - blocks sea, false - blocks land, indeterminate - allows all
//
// if (!hero->canWalkOnSea())
// blockLandSea = (map->getTile(hpos).tertype != TerrainTile::water); //block land if hero is on water and vice versa
// else
// blockLandSea = boost::logic::indeterminate;
2009-03-19 16:17:19 +02:00
2009-08-22 16:59:15 +03:00
const std : : vector < std : : vector < std : : vector < ui8 > > > & FoW = getPlayer ( hero - > tempOwner ) - > fogOfWarMap ;
2009-03-19 21:04:46 +02:00
//graph initialization
2009-03-19 16:17:19 +02:00
std : : vector < std : : vector < CPathNode > > graph ;
graph . resize ( map - > width ) ;
for ( size_t i = 0 ; i < graph . size ( ) ; + + i )
{
graph [ i ] . resize ( map - > height ) ;
for ( size_t j = 0 ; j < graph [ i ] . size ( ) ; + + j )
{
const TerrainTile * tinfo = & map - > terrain [ i ] [ j ] [ src . z ] ;
CPathNode & node = graph [ i ] [ j ] ;
2009-10-16 05:09:58 +03:00
node . accessible = ! tinfo - > blocked ;
2009-03-19 16:17:19 +02:00
node . dist = - 1 ;
node . theNodeBefore = NULL ;
node . visited = false ;
node . coord . x = i ;
node . coord . y = j ;
node . coord . z = dest . z ;
2010-03-21 00:17:19 +02:00
if ( ! tinfo - > entrableTerrain ( onLand , flying | | waterWalking )
2009-08-22 16:59:15 +03:00
| | ! FoW [ i ] [ j ] [ src . z ] //tile is covered by the FoW
2009-03-19 16:17:19 +02:00
)
{
2009-10-16 05:09:58 +03:00
node . accessible = false ;
2009-03-19 16:17:19 +02:00
}
}
}
2009-07-19 04:00:19 +03:00
//Special rules for the destination tile
{
const TerrainTile * t = & map - > terrain [ dest . x ] [ dest . y ] [ dest . z ] ;
CPathNode & d = graph [ dest . x ] [ dest . y ] ;
//tile may be blocked by blockvis / normal vis obj but it still must be accessible
if ( t - > visitable )
{
2009-10-16 05:09:58 +03:00
d . accessible = true ; //for allowing visiting objects
2009-07-19 04:00:19 +03:00
}
2010-03-21 00:17:19 +02:00
if ( onLand & & t - > tertype = = TerrainTile : : water ) //hero can walk only on land and dst lays on the water
2009-07-19 04:00:19 +03:00
{
size_t i = 0 ;
for ( ; i < t - > visitableObjects . size ( ) ; i + + )
2009-08-22 16:59:15 +03:00
if ( t - > visitableObjects [ i ] - > ID = = 8 | | t - > visitableObjects [ i ] - > ID = = HEROI_TYPE ) //it's a Boat
2009-07-19 04:00:19 +03:00
break ;
2009-10-16 05:09:58 +03:00
d . accessible = ( i < t - > visitableObjects . size ( ) ) ; //dest is accessible only if there is boat/hero
2009-07-19 04:00:19 +03:00
}
2010-03-21 00:17:19 +02:00
else if ( ! onLand & & t - > tertype ! = TerrainTile : : water ) //hero is moving by water
2009-07-19 04:00:19 +03:00
{
2009-10-16 05:09:58 +03:00
d . accessible = ( t - > siodmyTajemniczyBajt & 64 ) & & ! t - > blocked ; //tile is accessible if it's coastal and not blocked
2009-07-19 04:00:19 +03:00
}
}
2009-03-19 16:17:19 +02:00
//graph initialized
//initial tile - set cost on 0 and add to the queue
graph [ src . x ] [ src . y ] . dist = 0 ;
std : : queue < CPathNode > mq ;
mq . push ( graph [ src . x ] [ src . y ] ) ;
ui32 curDist = 0xffffffff ; //total cost of path - init with max possible val
std : : vector < int3 > neighbours ;
neighbours . reserve ( 8 ) ;
while ( ! mq . empty ( ) )
{
CPathNode & cp = graph [ mq . front ( ) . coord . x ] [ mq . front ( ) . coord . y ] ;
mq . pop ( ) ;
if ( cp . coord = = dest ) //it's destination tile
{
if ( cp . dist < curDist ) //that path is better than previous one
curDist = cp . dist ;
continue ;
}
else
{
if ( cp . dist > curDist ) //it's not dest and current length is greater than cost of already found path
continue ;
}
//add accessible neighbouring nodes to the queue
2010-07-10 05:15:49 +03:00
getNeighbours ( map - > getTile ( cp . coord ) , cp . coord , neighbours , boost : : logic : : indeterminate , true ) ;
2009-05-07 08:01:45 +03:00
for ( unsigned int i = 0 ; i < neighbours . size ( ) ; i + + )
2009-03-19 16:17:19 +02:00
{
CPathNode & dp = graph [ neighbours [ i ] . x ] [ neighbours [ i ] . y ] ;
2009-10-16 05:09:58 +03:00
if ( dp . accessible )
2009-03-19 16:17:19 +02:00
{
int cost = getMovementCost ( hero , cp . coord , dp . coord , hero - > movement - cp . dist ) ;
2009-10-16 05:09:58 +03:00
if ( ( dp . dist = = - 1 | | ( dp . dist > cp . dist + cost ) ) & & dp . accessible & & checkForVisitableDir ( cp . coord , dp . coord ) & & checkForVisitableDir ( dp . coord , cp . coord ) )
2009-03-19 16:17:19 +02:00
{
dp . dist = cp . dist + cost ;
dp . theNodeBefore = & cp ;
mq . push ( dp ) ;
}
}
}
}
CPathNode * curNode = & graph [ dest . x ] [ dest . y ] ;
if ( ! curNode - > theNodeBefore ) //destination is not accessible
2009-06-11 20:21:06 +03:00
return false ;
2009-03-19 16:17:19 +02:00
2009-06-11 20:21:06 +03:00
//fill ret with found path
ret . nodes . clear ( ) ;
2009-03-19 16:17:19 +02:00
while ( curNode - > coord ! = graph [ src . x ] [ src . y ] . coord )
{
2009-06-11 20:21:06 +03:00
ret . nodes . push_back ( * curNode ) ;
2009-03-19 16:17:19 +02:00
curNode = curNode - > theNodeBefore ;
}
2009-06-11 20:21:06 +03:00
ret . nodes . push_back ( graph [ src . x ] [ src . y ] ) ;
2009-03-19 16:17:19 +02:00
2009-06-11 20:21:06 +03:00
return true ;
2009-03-19 16:17:19 +02:00
}
2009-08-30 15:47:40 +03:00
void CGameState : : calculatePaths ( const CGHeroInstance * hero , CPathsInfo & out , int3 src , int movement )
{
2009-09-07 05:29:44 +03:00
assert ( hero ) ;
2009-12-19 14:31:57 +02:00
boost : : shared_lock < boost : : shared_mutex > lock ( * mx ) ;
2009-08-30 15:47:40 +03:00
if ( src . x < 0 )
src = hero - > getPosition ( false ) ;
if ( movement < 0 )
movement = hero - > movement ;
2009-09-07 05:29:44 +03:00
out . hero = hero ;
out . hpos = src ;
2009-08-30 15:47:40 +03:00
if ( ! map - > isInTheMap ( src ) /* || !map->isInTheMap(dest)*/ ) //check input
{
tlog1 < < " CGameState::calculatePaths: Hero outside the map? How dare you... \n " ;
return ;
}
tribool onLand ; //true - blocks sea, false - blocks land, indeterminate - allows all
if ( ! hero - > canWalkOnSea ( ) )
onLand = ( map - > getTile ( src ) . tertype ! = TerrainTile : : water ) ; //block land if hero is on water and vice versa
else
onLand = boost : : logic : : indeterminate ;
const std : : vector < std : : vector < std : : vector < ui8 > > > & FoW = getPlayer ( hero - > tempOwner ) - > fogOfWarMap ;
2010-05-15 18:00:19 +03:00
bool flying = hero - > hasBonusOfType ( Bonus : : FLYING_MOVEMENT ) ;
bool waterWalk = hero - > hasBonusOfType ( Bonus : : WATER_WALKING ) ;
2009-08-30 15:47:40 +03:00
//graph initialization
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 )
{
const TerrainTile * tinfo = & map - > terrain [ i ] [ j ] [ k ] ;
CGPathNode & node = graph [ i ] [ j ] [ k ] ;
2010-05-15 18:00:19 +03:00
node . accessible = ( tinfo - > blocked ? CGPathNode : : FLYABLE : CGPathNode : : ACCESSIBLE ) ;
if ( ! flying & & node . accessible = = CGPathNode : : FLYABLE )
{
node . accessible = CGPathNode : : BLOCKED ;
}
2009-08-30 15:47:40 +03:00
node . turns = 0xff ;
node . moveRemains = 0 ;
node . coord . x = i ;
node . coord . y = j ;
node . coord . z = k ;
node . land = tinfo - > tertype ! = TerrainTile : : water ;
2009-09-07 05:29:44 +03:00
node . theNodeBefore = NULL ;
2009-08-30 15:47:40 +03:00
2010-07-10 04:46:06 +03:00
bool leaveAsBlocked = false ;
2010-05-15 18:00:19 +03:00
if ( ( onLand | | indeterminate ( onLand ) ) & & ! node . land ) //it's sea and we cannot walk on sea
{
if ( waterWalk | | flying )
{
node . accessible = CGPathNode : : FLYABLE ;
}
else
{
node . accessible = CGPathNode : : BLOCKED ;
2010-07-10 04:46:06 +03:00
leaveAsBlocked = true ;
2010-05-15 18:00:19 +03:00
}
}
2009-08-30 15:47:40 +03:00
if ( tinfo - > tertype = = TerrainTile : : rock //it's rock
2010-05-15 18:00:19 +03:00
| | ! onLand & & node . land //it's land and we cannot walk on land (complementary condition is handled above)
2009-08-30 15:47:40 +03:00
| | ! FoW [ i ] [ j ] [ k ] //tile is covered by the FoW
2010-07-10 04:46:06 +03:00
| | leaveAsBlocked
2009-08-30 15:47:40 +03:00
)
{
node . accessible = CGPathNode : : BLOCKED ;
}
else if ( tinfo - > visitable )
{
2010-07-09 03:54:17 +03:00
//hero is protected in Sanctuary
if ( tinfo - > visitableObjects . front ( ) - > ID = = 80 & & tinfo - > visitableObjects . back ( ) - > ID = = HEROI_TYPE & & tinfo - > visitableObjects . back ( ) - > tempOwner ! = hero - > tempOwner )
node . accessible = CGPathNode : : BLOCKED ;
else
2009-08-30 15:47:40 +03:00
{
2010-07-09 03:54:17 +03:00
for ( size_t ii = 0 ; ii < tinfo - > visitableObjects . size ( ) ; ii + + )
2009-11-24 22:29:50 +02:00
{
2010-07-09 03:54:17 +03:00
const CGObjectInstance * const obj = tinfo - > visitableObjects [ ii ] ;
if ( obj - > getPassableness ( ) & 1 < < hero - > tempOwner ) //special object instance specific passableness flag - overwrites other accessibility flags
{
node . accessible = CGPathNode : : ACCESSIBLE ;
}
else if ( obj - > blockVisit )
{
node . accessible = CGPathNode : : BLOCKVIS ;
break ;
}
else if ( obj - > ID ! = EVENTI_TYPE ) //pathfinder should ignore placed events
{
node . accessible = CGPathNode : : VISITABLE ;
}
2009-11-24 22:29:50 +02:00
}
2009-08-30 15:47:40 +03:00
}
}
2010-05-06 15:13:31 +03:00
else if ( map - > isInTheMap ( guardingCreaturePosition ( int3 ( i , j , k ) ) )
& & tinfo - > blockingObjects . size ( ) = = 0 )
{
// Monster close by; blocked visit for battle.
node . accessible = CGPathNode : : BLOCKVIS ;
}
2009-08-30 15:47:40 +03:00
if ( onLand & & ! node . land ) //hero can walk only on land and tile lays on the water
{
size_t i = 0 ;
for ( ; i < tinfo - > visitableObjects . size ( ) ; i + + )
if ( tinfo - > visitableObjects [ i ] - > ID = = 8 | | tinfo - > visitableObjects [ i ] - > ID = = HEROI_TYPE ) //it's a Boat
break ;
if ( i < tinfo - > visitableObjects . size ( ) )
node . accessible = CGPathNode : : BLOCKVIS ; //dest is accessible only if there is boat/hero
}
else if ( ! onLand & & tinfo - > tertype ! = TerrainTile : : water ) //hero is moving by water
{
if ( ( tinfo - > siodmyTajemniczyBajt & 64 ) & & ! tinfo - > blocked )
2009-09-07 05:29:44 +03:00
node . accessible = CGPathNode : : VISITABLE ; //tile is accessible if it's coastal and not blocked
2009-08-30 15:47:40 +03:00
}
}
}
}
//graph initialized
//initial tile - set cost on 0 and add to the queue
graph [ src . x ] [ src . y ] [ src . z ] . turns = 0 ;
graph [ src . x ] [ src . y ] [ src . z ] . moveRemains = movement ;
std : : queue < CGPathNode * > mq ;
mq . push ( & graph [ src . x ] [ src . y ] [ src . z ] ) ;
2010-05-15 18:00:19 +03:00
//ui32 curDist = 0xffffffff; //total cost of path - init with max possible val
2009-08-30 15:47:40 +03:00
std : : vector < int3 > neighbours ;
neighbours . reserve ( 8 ) ;
while ( ! mq . empty ( ) )
{
CGPathNode * cp = mq . front ( ) ;
mq . pop ( ) ;
2010-05-26 12:47:53 +03:00
const int3 guardPosition = guardingCreaturePosition ( cp - > coord ) ;
const bool guardedPosition = ( guardPosition ! = int3 ( - 1 , - 1 , - 1 ) & & cp - > coord ! = src ) ;
2009-08-30 15:47:40 +03:00
const TerrainTile & ct = map - > getTile ( cp - > coord ) ;
int movement = cp - > moveRemains , turn = cp - > turns ;
if ( ! movement )
{
movement = hero - > maxMovePoints ( ct . tertype ! = TerrainTile : : water ) ;
turn + + ;
}
//add accessible neighbouring nodes to the queue
2010-07-10 05:15:49 +03:00
getNeighbours ( ct , cp - > coord , neighbours , boost : : logic : : indeterminate , ! onLand ) ;
2009-08-30 15:47:40 +03:00
for ( unsigned int i = 0 ; i < neighbours . size ( ) ; i + + )
{
2009-11-13 21:04:36 +02:00
int moveAtNextTile = movement ;
int turnAtNextTile = turn ;
2009-08-30 15:47:40 +03:00
const int3 & n = neighbours [ i ] ; //current neighbor
CGPathNode & dp = graph [ n . x ] [ n . y ] [ n . z ] ;
if ( ! checkForVisitableDir ( cp - > coord , dp . coord )
| | ! checkForVisitableDir ( dp . coord , cp - > coord )
| | dp . accessible = = CGPathNode : : BLOCKED )
{
continue ;
}
int cost = getMovementCost ( hero , cp - > coord , dp . coord , movement ) ;
int remains = movement - cost ;
2009-09-20 15:47:40 +03:00
if ( remains < 0 )
{
//occurs rarely, when hero with low movepoints tries to go leave the road
2009-11-13 21:04:36 +02:00
turnAtNextTile + + ;
moveAtNextTile = hero - > maxMovePoints ( ct . tertype ! = TerrainTile : : water ) ;
cost = getMovementCost ( hero , cp - > coord , dp . coord , moveAtNextTile ) ; //cost must be updated, movement points changed :(
remains = moveAtNextTile - cost ;
2009-09-20 15:47:40 +03:00
}
2010-05-06 15:13:31 +03:00
const bool neighborIsGuard = guardingCreaturePosition ( cp - > coord ) = = dp . coord ;
if ( ( dp . turns = = 0xff //we haven't been here before
2009-11-13 21:04:36 +02:00
| | dp . turns > turnAtNextTile
| | ( dp . turns > = turnAtNextTile & & dp . moveRemains < remains ) ) //this route is faster
2010-05-06 15:13:31 +03:00
& & ( ! guardedPosition | | neighborIsGuard ) ) // Can step into tile of guard
2009-08-30 15:47:40 +03:00
{
2010-05-06 15:13:31 +03:00
2009-09-11 08:45:40 +03:00
assert ( & dp ! = cp - > theNodeBefore ) ; //two tiles can't point to each other
2009-08-30 15:47:40 +03:00
dp . moveRemains = remains ;
2009-11-13 21:04:36 +02:00
dp . turns = turnAtNextTile ;
2009-08-30 15:47:40 +03:00
dp . theNodeBefore = cp ;
2010-05-06 15:13:31 +03:00
const bool guardedNeighbor = guardingCreaturePosition ( dp . coord ) ! = int3 ( - 1 , - 1 , - 1 ) ;
2010-05-26 12:47:53 +03:00
//const bool positionIsGuard = guardingCreaturePosition(cp->coord) == cp->coord; //can this be true? hero never passes from monster tile...
2010-05-06 15:13:31 +03:00
2010-05-15 18:00:19 +03:00
if ( dp . accessible = = CGPathNode : : ACCESSIBLE | | dp . accessible = = CGPathNode : : FLYABLE
2010-05-26 12:47:53 +03:00
| | ( guardedNeighbor & & ! guardedPosition ) ) // Can step into a hostile tile once.
2009-08-30 15:47:40 +03:00
{
mq . push ( & dp ) ;
}
}
} //neighbours loop
} //queue loop
}
2009-08-28 12:03:58 +03:00
2010-05-06 15:13:31 +03:00
/**
* Tells if the tile is guarded by a monster as well as the position
* of the monster that will attack on it .
*
* @ return int3 ( - 1 , - 1 , - 1 ) if the tile is unguarded , or the position of
* the monster guarding the tile .
*/
int3 CGameState : : guardingCreaturePosition ( int3 pos ) const
{
2010-05-27 00:59:58 +03:00
const int3 originalPos = pos ;
2010-05-06 15:13:31 +03:00
// Give monster at position priority.
if ( ! map - > isInTheMap ( pos ) )
return int3 ( - 1 , - 1 , - 1 ) ;
const TerrainTile & posTile = map - > terrain [ pos . x ] [ pos . y ] [ pos . z ] ;
2010-05-27 00:59:58 +03:00
if ( posTile . visitable )
{
BOOST_FOREACH ( CGObjectInstance * obj , posTile . visitableObjects )
{
if ( obj - > blockVisit )
{
if ( obj - > ID = = 54 ) // Monster
return pos ;
else
return int3 ( - 1 , - 1 , - 1 ) ; //blockvis objects are not guarded by neighbouring creatures
2010-05-06 15:13:31 +03:00
}
}
}
// See if there are any monsters adjacent.
pos - = int3 ( 1 , 1 , 0 ) ; // Start with top left.
2010-05-27 00:59:58 +03:00
for ( int dx = 0 ; dx < 3 ; dx + + )
{
for ( int dy = 0 ; dy < 3 ; dy + + )
{
if ( map - > isInTheMap ( pos ) )
{
2010-05-06 15:13:31 +03:00
TerrainTile & tile = map - > terrain [ pos . x ] [ pos . y ] [ pos . z ] ;
2010-07-12 13:20:25 +03:00
if ( tile . visitable & & ( tile . tertype = = TerrainTile : : water ) = = ( posTile . tertype = = TerrainTile : : water ) )
2010-05-27 00:59:58 +03:00
{
BOOST_FOREACH ( CGObjectInstance * obj , tile . visitableObjects )
{
if ( obj - > ID = = 54 & & checkForVisitableDir ( pos , & map - > getTile ( originalPos ) , originalPos ) ) // Monster being able to attack investigated tile
{
2010-05-06 15:13:31 +03:00
return pos ;
}
}
}
}
pos . y + + ;
}
pos . y - = 3 ;
pos . x + + ;
}
return int3 ( - 1 , - 1 , - 1 ) ;
}
2009-07-30 15:49:45 +03:00
bool CGameState : : isVisible ( int3 pos , int player )
{
2009-07-31 14:20:53 +03:00
if ( player = = 255 ) //neutral player
return false ;
2009-07-30 15:49:45 +03:00
return players [ player ] . fogOfWarMap [ pos . x ] [ pos . y ] [ pos . z ] ;
}
bool CGameState : : isVisible ( const CGObjectInstance * obj , int player )
{
2009-07-31 14:20:53 +03:00
if ( player = = 255 ) //neutral player
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 )
{
int3 pos = obj - > pos + int3 ( fx - 7 , fy - 5 , 0 ) ;
if ( map - > isInTheMap ( pos )
& & ! ( ( obj - > defInfo - > blockMap [ fy ] > > ( 7 - fx ) ) & 1 )
& & isVisible ( pos , player ) )
return true ;
}
}
return false ;
}
2009-03-19 16:17:19 +02:00
bool CGameState : : checkForVisitableDir ( const int3 & src , const int3 & dst ) const
{
const TerrainTile * pom = & map - > getTile ( dst ) ;
2009-08-30 15:47:40 +03:00
return checkForVisitableDir ( src , pom , dst ) ;
}
bool CGameState : : checkForVisitableDir ( const int3 & src , const TerrainTile * pom , const int3 & dst ) const
{
2009-05-07 08:01:45 +03:00
for ( unsigned int b = 0 ; b < pom - > visitableObjects . size ( ) ; + + b ) //checking destination tile
2009-03-19 16:17:19 +02:00
{
if ( ! vstd : : contains ( pom - > blockingObjects , pom - > visitableObjects [ b ] ) ) //this visitable object is not blocking, ignore
continue ;
CGDefInfo * di = pom - > visitableObjects [ b ] - > defInfo ;
if ( ( dst . x = = src . x - 1 & & dst . y = = src . y - 1 ) & & ! ( di - > visitDir & ( 1 < < 4 ) ) )
{
return false ;
}
if ( ( dst . x = = src . x & & dst . y = = src . y - 1 ) & & ! ( di - > visitDir & ( 1 < < 5 ) ) )
{
return false ;
}
if ( ( dst . x = = src . x + 1 & & dst . y = = src . y - 1 ) & & ! ( di - > visitDir & ( 1 < < 6 ) ) )
{
return false ;
}
if ( ( dst . x = = src . x + 1 & & dst . y = = src . y ) & & ! ( di - > visitDir & ( 1 < < 7 ) ) )
{
return false ;
}
if ( ( dst . x = = src . x + 1 & & dst . y = = src . y + 1 ) & & ! ( di - > visitDir & ( 1 < < 0 ) ) )
{
return false ;
}
if ( ( dst . x = = src . x & & dst . y = = src . y + 1 ) & & ! ( di - > visitDir & ( 1 < < 1 ) ) )
{
return false ;
}
if ( ( dst . x = = src . x - 1 & & dst . y = = src . y + 1 ) & & ! ( di - > visitDir & ( 1 < < 2 ) ) )
{
return false ;
}
if ( ( dst . x = = src . x - 1 & & dst . y = = src . y ) & & ! ( di - > visitDir & ( 1 < < 3 ) ) )
{
return false ;
}
}
return true ;
}
2010-04-06 16:19:54 +03:00
std : : pair < ui32 , ui32 > BattleInfo : : calculateDmgRange ( const CStack * attacker , const CStack * defender , const CGHeroInstance * attackerHero , const CGHeroInstance * defendingHero , bool shooting , ui8 charge , bool lucky )
2008-08-02 18:08:03 +03:00
{
2010-04-06 16:19:54 +03:00
float additiveBonus = 1.0f , multBonus = 1.0f ,
2010-07-16 09:18:41 +03:00
minDmg = attacker - > getMinDamage ( ) * attacker - > count ,
maxDmg = attacker - > getMaxDamage ( ) * attacker - > count ;
2009-03-28 02:38:48 +02:00
2010-05-02 21:20:26 +03:00
if ( attacker - > type - > idNumber = = 149 ) //arrow turret
2009-09-04 17:11:42 +03:00
{
switch ( attacker - > position )
{
case - 2 : //keep
minDmg = 15 ;
maxDmg = 15 ;
break ;
case - 3 : case - 4 : //turrets
minDmg = 7.5f ;
maxDmg = 7.5f ;
break ;
}
}
2010-05-02 21:20:26 +03:00
if ( attacker - > hasBonusOfType ( Bonus : : SIEGE_WEAPON ) & & attacker - > type - > idNumber ! = 149 ) //any siege weapon, but only ballista can attack (second condition - not arrow turret)
2009-07-30 15:49:45 +03:00
{ //minDmg and maxDmg are multiplied by hero attack + 1
minDmg * = attackerHero - > getPrimSkillLevel ( 0 ) + 1 ;
maxDmg * = attackerHero - > getPrimSkillLevel ( 0 ) + 1 ;
}
2010-04-06 16:19:54 +03:00
int attackDefenceDifference = 0 ;
2010-05-02 21:20:26 +03:00
if ( attacker - > hasBonusOfType ( Bonus : : GENERAL_ATTACK_REDUCTION ) )
2009-08-07 14:22:17 +03:00
{
2010-05-02 21:20:26 +03:00
float multAttackReduction = attacker - > valOfBonuses ( Bonus : : GENERAL_ATTACK_REDUCTION , - 1024 ) / 100.0f ;
2010-04-06 16:19:54 +03:00
attackDefenceDifference = attacker - > Attack ( ) * multAttackReduction ;
2009-08-07 14:22:17 +03:00
}
else
{
2010-04-06 16:19:54 +03:00
attackDefenceDifference = attacker - > Attack ( ) ;
2010-03-12 21:05:23 +02:00
}
2010-05-02 21:20:26 +03:00
if ( attacker - > hasBonusOfType ( Bonus : : ENEMY_DEFENCE_REDUCTION ) )
2010-03-12 21:05:23 +02:00
{
2010-05-02 21:20:26 +03:00
float multDefenceReduction = ( 100.0f - attacker - > valOfBonuses ( Bonus : : ENEMY_DEFENCE_REDUCTION , - 1024 ) ) / 100.0f ;
2010-04-06 16:19:54 +03:00
attackDefenceDifference - = defender - > Defense ( ) * multDefenceReduction ;
2010-03-12 21:05:23 +02:00
}
else
{
2010-04-06 16:19:54 +03:00
attackDefenceDifference - = defender - > Defense ( ) ;
2009-08-07 14:22:17 +03:00
}
2009-03-28 02:38:48 +02:00
//calculating total attack/defense skills modifier
2009-05-01 16:42:41 +03:00
2010-05-02 21:20:26 +03:00
if ( shooting ) //precision handling (etc.)
attackDefenceDifference + = attacker - > getBonuses ( Selector : : typeSybtype ( Bonus : : PRIMARY_SKILL , PrimarySkill : : ATTACK ) , Selector : : effectRange ( Bonus : : ONLY_DISTANCE_FIGHT ) ) . totalValue ( ) ;
else //bloodlust handling (etc.)
attackDefenceDifference + = attacker - > getBonuses ( Selector : : typeSybtype ( Bonus : : PRIMARY_SKILL , PrimarySkill : : ATTACK ) , Selector : : effectRange ( Bonus : : ONLY_MELEE_FIGHT ) ) . totalValue ( ) ;
2009-05-01 16:42:41 +03:00
if ( attacker - > getEffect ( 55 ) ) //slayer handling
2008-12-06 18:45:54 +02:00
{
2009-05-01 16:42:41 +03:00
std : : vector < int > affectedIds ;
2010-03-03 13:18:08 +02:00
int spLevel = attacker - > getEffect ( 55 ) - > level ;
for ( int g = 0 ; g < VLC - > creh - > creatures . size ( ) ; + + g )
2009-05-01 16:42:41 +03:00
{
2010-05-02 21:20:26 +03:00
BOOST_FOREACH ( const Bonus & b , VLC - > creh - > creatures [ g ] - > bonuses )
2009-05-01 16:42:41 +03:00
{
2010-05-02 21:20:26 +03:00
if ( ( b . type = = Bonus : : KING3 & & spLevel > = 3 ) | | //expert
( b . type = = Bonus : : KING2 & & spLevel > = 2 ) | | //adv +
( b . type = = Bonus : : KING1 & & spLevel > = 0 ) ) //none or basic +
2010-03-03 13:18:08 +02:00
{
affectedIds . push_back ( g ) ;
break ;
}
2009-05-01 16:42:41 +03:00
}
}
2010-03-03 13:18:08 +02:00
2009-05-07 08:01:45 +03:00
for ( unsigned int g = 0 ; g < affectedIds . size ( ) ; + + g )
2009-05-01 16:42:41 +03:00
{
2010-05-02 21:20:26 +03:00
if ( defender - > type - > idNumber = = affectedIds [ g ] )
2009-05-01 16:42:41 +03:00
{
2010-04-06 16:19:54 +03:00
attackDefenceDifference + = VLC - > spellh - > spells [ 55 ] . powers [ attacker - > getEffect ( 55 ) - > level ] ;
2009-05-01 16:42:41 +03:00
break ;
}
}
2008-12-06 18:45:54 +02:00
}
2008-08-02 18:08:03 +03:00
2009-03-28 02:38:48 +02:00
//bonus from attack/defense skills
2010-04-06 16:19:54 +03:00
if ( attackDefenceDifference < 0 ) //decreasing dmg
2008-08-02 18:08:03 +03:00
{
2010-04-06 16:19:54 +03:00
float dec = 0.025f * ( - attackDefenceDifference ) ;
if ( dec > 0.7f )
2008-08-02 18:08:03 +03:00
{
2010-05-07 15:29:41 +03:00
multBonus * = 0.3f ; //1.0 - 0.7
2008-08-02 18:08:03 +03:00
}
else
{
2010-05-07 15:29:41 +03:00
multBonus * = 1.0f - dec ;
2008-08-02 18:08:03 +03:00
}
}
else //increasing dmg
{
2010-04-06 16:19:54 +03:00
float inc = 0.05f * attackDefenceDifference ;
if ( inc > 4.0f )
2008-08-02 18:08:03 +03:00
{
2010-04-06 16:19:54 +03:00
additiveBonus + = 4.0f ;
2008-08-02 18:08:03 +03:00
}
else
{
2010-04-06 16:19:54 +03:00
additiveBonus + = inc ;
2008-08-02 18:08:03 +03:00
}
}
2010-04-06 16:19:54 +03:00
2009-03-28 02:38:48 +02:00
2010-04-06 16:19:54 +03:00
//applying jousting bonus
2010-05-02 21:20:26 +03:00
if ( attacker - > hasBonusOfType ( Bonus : : JOUSTING ) & & ! defender - > hasBonusOfType ( Bonus : : CHARGE_IMMUNITY ) )
2010-04-06 16:19:54 +03:00
additiveBonus + = charge * 0.05f ;
* support for new hero bonuses (BLOCK_MORALE, SECONDARY_SKILL_PREMY (archery), AIR_SPELL_DMG_PREMY, EARTH_SPELL_DMG_PREMY, FIRE_SPELL_DMG_PREMY, WATER_SPELL_DMG_PREMY, BLOCK_SPELLS_ABOVE_LEVEL, SPELL_IMMUNITY, BLOCK_MORALE, FIRE_SPELLS, AIR_SPELLS, WATER_SPELLS, EARTH_SPELLS, SPELL, SPELLS_OF_LEVEL). It means that following artifacts are now supported:
- Orb of the Firmament
- Orb of Silt
- Orb of Tempestuous Fire
- Orb of Driving Rain
- Bow of Elven Cherrywood
- Bowstring of the Unicorn's Mane
- Angel Feather Arrows
- Tome of Fire Magic
- Tome of Air Magic
- Tome of Water Magic
- Tome of Earth Magic
- Recanter's Cloak
- Orb of Inhibition
- Pendant of Dispassion
- Pendant of Second Sight
- Pendant of Holiness
- Pendant of Life
- Pendant of Death
- Pendant of Free Will
- Pendant of Negativity
- Pendant of Total Recall
- Spellbinder's Hat
- Spirit of Oppression
- Sphere of Permanence
I hope I listed them all here :). Please try them and report if something's wrong.
2009-05-03 19:14:16 +03:00
//handling secondary abilities and artifacts giving premies to them
2008-09-29 14:03:30 +03:00
if ( attackerHero )
{
if ( shooting )
{
2010-07-17 20:02:11 +03:00
additiveBonus + = attackerHero - > valOfBonuses ( Bonus : : SECONDARY_SKILL_PREMY , 1 ) / 100.0f ;
2008-09-29 14:03:30 +03:00
}
else
{
2010-07-17 20:02:11 +03:00
additiveBonus + = attackerHero - > valOfBonuses ( Bonus : : SECONDARY_SKILL_PREMY , 22 ) / 100.0f ;
2008-09-29 14:03:30 +03:00
}
}
2010-04-06 16:19:54 +03:00
2008-09-29 14:03:30 +03:00
if ( defendingHero )
{
2010-07-23 15:02:15 +03:00
multBonus * = ( std : : max ( 0 , 100 - defendingHero - > valOfBonuses ( Bonus : : SECONDARY_SKILL_PREMY , 23 ) ) ) / 100.0f ;
2008-09-29 14:03:30 +03:00
}
2009-08-23 16:41:57 +03:00
//handling hate effect
2010-05-02 21:20:26 +03:00
if ( attacker - > hasBonusOfType ( Bonus : : HATE , defender - > type - > idNumber ) )
2010-04-06 16:19:54 +03:00
additiveBonus + = 0.5f ;
//luck bonus
if ( lucky )
{
additiveBonus + = 1.0f ;
}
2009-08-23 16:41:57 +03:00
2008-12-06 18:45:54 +02:00
//handling spell effects
2010-05-02 21:20:26 +03:00
if ( ! shooting & & defender - > hasBonusOfType ( Bonus : : GENERAL_DAMAGE_REDUCTION , 0 ) ) //eg. shield
2008-12-06 18:45:54 +02:00
{
2010-05-02 21:20:26 +03:00
multBonus * = float ( defender - > valOfBonuses ( Bonus : : GENERAL_DAMAGE_REDUCTION , 0 ) ) / 100.0f ;
2008-12-06 18:45:54 +02:00
}
2010-05-02 21:20:26 +03:00
else if ( shooting & & defender - > hasBonusOfType ( Bonus : : GENERAL_DAMAGE_REDUCTION , 1 ) ) //eg. air shield
2008-12-06 18:45:54 +02:00
{
2010-05-02 21:20:26 +03:00
multBonus * = float ( defender - > valOfBonuses ( Bonus : : GENERAL_DAMAGE_REDUCTION , 1 ) ) / 100.0f ;
2008-12-06 18:45:54 +02:00
}
2009-03-28 02:38:48 +02:00
if ( attacker - > getEffect ( 42 ) ) //curse handling (partial, the rest is below)
2008-12-06 18:45:54 +02:00
{
2010-04-06 16:19:54 +03:00
multBonus * = 0.8f * float ( VLC - > spellh - > spells [ 42 ] . powers [ attacker - > getEffect ( 42 ) - > level ] ) ; //the second factor is 1 or 0
2008-12-06 18:45:54 +02:00
}
2008-08-02 18:08:03 +03:00
2010-04-06 16:19:54 +03:00
class HLP
{
public :
static bool hasAdvancedAirShield ( const CStack * stack )
{
for ( int g = 0 ; g < stack - > effects . size ( ) ; + + g )
{
if ( stack - > effects [ g ] . id = = 28 & & stack - > effects [ g ] . level > = 2 )
{
return true ;
}
}
return false ;
}
} ;
//wall / distance penalty + advanced air shield
2010-05-20 13:18:30 +03:00
if ( shooting & & ! NBonus : : hasOfType ( attackerHero , Bonus : : NO_SHOTING_PENALTY ) & & (
2010-04-06 16:19:54 +03:00
hasDistancePenalty ( attacker - > ID , defender - > position ) | | hasWallPenalty ( attacker - > ID , defender - > position ) | |
HLP : : hasAdvancedAirShield ( defender ) )
)
{
multBonus * = 0.5 ;
}
2010-05-07 15:40:56 +03:00
if ( ! shooting & & attacker - > hasBonusOfType ( Bonus : : SHOOTER ) & & ! attacker - > hasBonusOfType ( Bonus : : NO_MELEE_PENALTY ) )
{
multBonus * = 0.5 ;
}
2009-03-28 02:38:48 +02:00
2010-04-06 16:19:54 +03:00
minDmg * = additiveBonus * multBonus ;
maxDmg * = additiveBonus * multBonus ;
2009-03-28 02:38:48 +02:00
2010-03-26 20:46:39 +02:00
std : : pair < ui32 , ui32 > returnedVal ;
2009-03-28 02:38:48 +02:00
if ( attacker - > getEffect ( 42 ) ) //curse handling (rest)
{
2009-04-21 20:32:43 +03:00
minDmg - = VLC - > spellh - > spells [ 42 ] . powers [ attacker - > getEffect ( 42 ) - > level ] ;
2010-03-26 20:46:39 +02:00
returnedVal = std : : make_pair ( int ( minDmg ) , int ( minDmg ) ) ;
2009-03-28 02:38:48 +02:00
}
else if ( attacker - > getEffect ( 41 ) ) //bless handling
{
2009-04-21 20:32:43 +03:00
maxDmg + = VLC - > spellh - > spells [ 41 ] . powers [ attacker - > getEffect ( 41 ) - > level ] ;
2010-03-26 20:46:39 +02:00
returnedVal = std : : make_pair ( int ( maxDmg ) , int ( maxDmg ) ) ;
2009-03-28 02:38:48 +02:00
}
else
{
2010-03-26 20:46:39 +02:00
returnedVal = std : : make_pair ( int ( minDmg ) , int ( maxDmg ) ) ;
2009-03-28 02:38:48 +02:00
}
2010-03-26 20:46:39 +02:00
//damage cannot be less than 1
2010-04-02 05:07:40 +03:00
amax ( returnedVal . first , 1 ) ;
amax ( returnedVal . second , 1 ) ;
2010-03-26 20:46:39 +02:00
return returnedVal ;
2009-08-29 20:09:07 +03:00
}
2010-04-06 16:19:54 +03:00
ui32 BattleInfo : : calculateDmg ( const CStack * attacker , const CStack * defender , const CGHeroInstance * attackerHero , const CGHeroInstance * defendingHero , bool shooting , ui8 charge , bool lucky )
2009-08-29 20:09:07 +03:00
{
2010-04-06 16:19:54 +03:00
std : : pair < ui32 , ui32 > range = calculateDmgRange ( attacker , defender , attackerHero , defendingHero , shooting , charge , lucky ) ;
2009-08-29 20:09:07 +03:00
if ( range . first ! = range . second )
2010-04-06 16:19:54 +03:00
{
int valuesToAverage [ 10 ] ;
2010-05-02 21:20:26 +03:00
int howManyToAv = std : : min < ui32 > ( 10 , attacker - > count ) ;
2010-04-06 16:19:54 +03:00
for ( int g = 0 ; g < howManyToAv ; + + g )
{
valuesToAverage [ g ] = range . first + rand ( ) % ( range . second - range . first + 1 ) ;
}
return std : : accumulate ( valuesToAverage , valuesToAverage + howManyToAv , 0 ) / howManyToAv ;
}
2009-08-29 20:09:07 +03:00
else
return range . first ;
2008-08-17 22:15:31 +03:00
}
2008-09-09 10:05:02 +03:00
2009-09-24 16:23:52 +03:00
void BattleInfo : : calculateCasualties ( std : : map < ui32 , si32 > * casualties ) const
2008-09-09 10:05:02 +03:00
{
2009-05-07 08:01:45 +03:00
for ( unsigned int i = 0 ; i < stacks . size ( ) ; i + + ) //setting casualties
2008-09-09 10:05:02 +03:00
{
2009-09-24 16:23:52 +03:00
const CStack * const st = stacks [ i ] ;
2010-05-02 21:20:26 +03:00
si32 killed = ( st - > alive ( ) ? st - > baseAmount - st - > count : st - > baseAmount ) ;
2009-09-24 16:23:52 +03:00
amax ( killed , 0 ) ;
2009-10-02 01:12:30 +03:00
if ( killed )
2010-05-02 21:20:26 +03:00
casualties [ ! st - > attackerOwned ] [ st - > type - > idNumber ] + = killed ;
2008-09-09 10:05:02 +03:00
}
2008-11-15 17:26:08 +02:00
}
2009-05-10 16:00:15 +03:00
si8 CGameState : : battleMaxSpellLevel ( )
{
if ( ! curB ) //there is not battle
{
tlog1 < < " si8 CGameState::maxSpellLevel() call when there is no battle! " < < std : : endl ;
throw " si8 CGameState::maxSpellLevel() call when there is no battle! " ;
}
si8 levelLimit = SPELL_LEVELS ;
2009-10-06 03:32:33 +03:00
const CGHeroInstance * h1 = curB - > heroes [ 0 ] ;
2009-05-10 16:00:15 +03:00
if ( h1 )
{
2010-05-02 21:20:26 +03:00
for ( std : : list < Bonus > : : const_iterator i = h1 - > bonuses . begin ( ) ; i ! = h1 - > bonuses . end ( ) ; i + + )
if ( i - > type = = Bonus : : BLOCK_SPELLS_ABOVE_LEVEL )
2009-05-10 16:00:15 +03:00
amin ( levelLimit , i - > val ) ;
}
2009-10-06 03:32:33 +03:00
const CGHeroInstance * h2 = curB - > heroes [ 1 ] ;
2009-05-10 16:00:15 +03:00
if ( h2 )
{
2010-05-02 21:20:26 +03:00
for ( std : : list < Bonus > : : const_iterator i = h2 - > bonuses . begin ( ) ; i ! = h2 - > bonuses . end ( ) ; i + + )
if ( i - > type = = Bonus : : BLOCK_SPELLS_ABOVE_LEVEL )
2009-05-10 16:00:15 +03:00
amin ( levelLimit , i - > val ) ;
}
return levelLimit ;
}
2010-02-23 17:39:31 +02:00
std : : set < CStack * > BattleInfo : : getAttackedCreatures ( const CSpell * s , int skillLevel , ui8 attackerOwner , int destinationTile )
2009-05-07 18:19:52 +03:00
{
2010-02-23 17:39:31 +02:00
std : : set < ui16 > attackedHexes = s - > rangeInHexes ( destinationTile , skillLevel ) ;
2009-09-07 05:29:44 +03:00
std : : set < CStack * > attackedCres ; /*std::set to exclude multiple occurrences of two hex creatures*/
2009-08-05 15:46:08 +03:00
bool onlyAlive = s - > id ! = 38 & & s - > id ! = 39 ; //when casting resurrection or animate dead we should be allow to select dead stack
2009-09-07 05:29:44 +03:00
if ( s - > id = = 24 | | s - > id = = 25 | | s - > id = = 26 ) //death ripple, destroy undead and Armageddon
2009-05-07 18:19:52 +03:00
{
for ( int it = 0 ; it < stacks . size ( ) ; + + it )
{
2010-05-02 21:20:26 +03:00
if ( ( s - > id = = 24 & & ! stacks [ it ] - > type - > isUndead ( ) ) //death ripple
| | ( s - > id = = 25 & & stacks [ it ] - > type - > isUndead ( ) ) //destroy undead
2009-09-07 05:29:44 +03:00
| | ( s - > id = = 26 ) //Armageddon
2009-05-07 18:19:52 +03:00
)
{
2009-09-17 15:59:04 +03:00
if ( stacks [ it ] - > alive ( ) )
attackedCres . insert ( stacks [ it ] ) ;
2009-05-07 18:19:52 +03:00
}
}
}
2009-08-04 20:05:49 +03:00
else if ( VLC - > spellh - > spells [ s - > id ] . attributes . find ( " CREATURE_TARGET_1 " ) ! = std : : string : : npos
| | VLC - > spellh - > spells [ s - > id ] . attributes . find ( " CREATURE_TARGET_2 " ) ! = std : : string : : npos ) //spell to be cast on a specific creature but massive on expert
2009-05-07 18:19:52 +03:00
{
2010-02-23 17:39:31 +02:00
if ( skillLevel < 3 ) /*not expert */
2009-05-07 18:19:52 +03:00
{
2009-08-05 15:46:08 +03:00
CStack * st = getStackT ( destinationTile , onlyAlive ) ;
2009-05-07 18:19:52 +03:00
if ( st )
attackedCres . insert ( st ) ;
}
else
{
for ( int it = 0 ; it < stacks . size ( ) ; + + it )
{
/*if it's non negative spell and our unit or non positive spell and hostile unit */
2010-02-23 17:39:31 +02:00
if ( ( VLC - > spellh - > spells [ s - > id ] . positiveness > = 0 & & stacks [ it ] - > owner = = attackerOwner )
| | ( VLC - > spellh - > spells [ s - > id ] . positiveness < = 0 & & stacks [ it ] - > owner ! = attackerOwner )
2009-05-07 18:19:52 +03:00
)
{
2009-08-05 15:46:08 +03:00
if ( ! onlyAlive | | stacks [ it ] - > alive ( ) )
attackedCres . insert ( stacks [ it ] ) ;
2009-05-07 18:19:52 +03:00
}
}
} //if(caster->getSpellSchoolLevel(s) < 3)
}
else if ( VLC - > spellh - > spells [ s - > id ] . attributes . find ( " CREATURE_TARGET " ) ! = std : : string : : npos ) //spell to be cast on one specific creature
{
2009-08-05 15:46:08 +03:00
CStack * st = getStackT ( destinationTile , onlyAlive ) ;
2009-05-07 18:19:52 +03:00
if ( st )
attackedCres . insert ( st ) ;
}
else //custom range from attackedHexes
{
for ( std : : set < ui16 > : : iterator it = attackedHexes . begin ( ) ; it ! = attackedHexes . end ( ) ; + + it )
{
2009-08-05 15:46:08 +03:00
CStack * st = getStackT ( * it , onlyAlive ) ;
2009-05-07 18:19:52 +03:00
if ( st )
attackedCres . insert ( st ) ;
}
}
return attackedCres ;
}
2010-05-19 21:06:16 +03:00
int BattleInfo : : calculateSpellDuration ( const CSpell * spell , const CGHeroInstance * caster , int usedSpellPower )
2009-08-06 17:02:21 +03:00
{
2010-03-02 13:40:29 +02:00
if ( ! caster ) //TODO: something better
2010-05-19 21:06:16 +03:00
return std : : max ( 5 , usedSpellPower ) ;
2009-08-06 17:02:21 +03:00
switch ( spell - > id )
{
case 56 : //frenzy
return 1 ;
default : //other spells
2010-05-02 21:20:26 +03:00
return caster - > getPrimSkillLevel ( 2 ) + caster - > valOfBonuses ( Bonus : : SPELL_DURATION ) ;
2009-08-06 17:02:21 +03:00
}
}
2010-05-02 21:20:26 +03:00
CStack * BattleInfo : : generateNewStack ( const CStackInstance & base , int stackID , bool attackerOwned , int slot , int /*TerrainTile::EterrainType*/ terrain , int position ) const
2009-08-06 17:02:21 +03:00
{
2010-05-02 21:20:26 +03:00
CStack * ret = new CStack ( & base , attackerOwned ? side1 : side2 , stackID , attackerOwned , slot ) ;
2009-08-06 17:02:21 +03:00
//native terrain bonuses
2010-05-02 21:20:26 +03:00
int faction = ret - > type - > faction ;
2009-08-06 17:02:21 +03:00
if ( faction > = 0 & & VLC - > heroh - > nativeTerrains [ faction ] = = terrain )
{
2010-05-02 21:20:26 +03:00
ret - > bonuses . push_back ( makeFeature ( Bonus : : STACKS_SPEED , Bonus : : ONE_BATTLE , 0 , 1 , Bonus : : TERRAIN_NATIVE ) ) ;
ret - > bonuses . push_back ( makeFeature ( Bonus : : PRIMARY_SKILL , Bonus : : ONE_BATTLE , PrimarySkill : : ATTACK , 1 , Bonus : : TERRAIN_NATIVE ) ) ;
ret - > bonuses . push_back ( makeFeature ( Bonus : : PRIMARY_SKILL , Bonus : : ONE_BATTLE , PrimarySkill : : DEFENSE , 1 , Bonus : : TERRAIN_NATIVE ) ) ;
2009-08-06 17:02:21 +03:00
}
ret - > position = position ;
return ret ;
}
2009-09-02 17:10:19 +03:00
ui32 BattleInfo : : getSpellCost ( const CSpell * sp , const CGHeroInstance * caster ) const
2009-08-23 16:41:57 +03:00
{
2010-03-11 01:16:30 +02:00
ui32 ret = caster - > getSpellCost ( sp ) ;
2009-08-23 16:41:57 +03:00
2010-02-23 17:39:31 +02:00
//checking for friendly stacks reducing cost of the spell and
//enemy stacks increasing it
2009-08-23 16:41:57 +03:00
si32 manaReduction = 0 ;
2010-02-23 17:39:31 +02:00
si32 manaIncrease = 0 ;
2009-08-23 16:41:57 +03:00
for ( int g = 0 ; g < stacks . size ( ) ; + + g )
{
2010-05-02 21:20:26 +03:00
if ( stacks [ g ] - > owner = = caster - > tempOwner & & stacks [ g ] - > hasBonusOfType ( Bonus : : CHANGES_SPELL_COST_FOR_ALLY ) )
2009-08-23 16:41:57 +03:00
{
2010-05-02 21:20:26 +03:00
amin ( manaReduction , stacks [ g ] - > valOfBonuses ( Bonus : : CHANGES_SPELL_COST_FOR_ALLY ) ) ;
2009-08-23 16:41:57 +03:00
}
2010-05-02 21:20:26 +03:00
if ( stacks [ g ] - > owner ! = caster - > tempOwner & & stacks [ g ] - > hasBonusOfType ( Bonus : : CHANGES_SPELL_COST_FOR_ENEMY ) )
2010-02-23 17:39:31 +02:00
{
2010-05-02 21:20:26 +03:00
amax ( manaIncrease , stacks [ g ] - > valOfBonuses ( Bonus : : CHANGES_SPELL_COST_FOR_ENEMY ) ) ;
2010-02-23 17:39:31 +02:00
}
2009-08-23 16:41:57 +03:00
}
2010-02-23 17:39:31 +02:00
return ret + manaReduction + manaIncrease ;
2009-08-23 16:41:57 +03:00
}
2009-09-02 17:10:19 +03:00
int BattleInfo : : hexToWallPart ( int hex ) const
2009-09-01 16:54:13 +03:00
{
if ( siege = = 0 ) //there is no battle!
return - 1 ;
static const std : : pair < int , int > attackable [ ] = //potentially attackable parts of wall
2009-09-02 17:10:19 +03:00
{ std : : make_pair ( 50 , 0 ) , std : : make_pair ( 183 , 1 ) , std : : make_pair ( 182 , 2 ) , std : : make_pair ( 130 , 3 ) ,
2009-09-01 16:54:13 +03:00
std : : make_pair ( 62 , 4 ) , std : : make_pair ( 29 , 5 ) , std : : make_pair ( 12 , 6 ) , std : : make_pair ( 95 , 7 ) , std : : make_pair ( 96 , 7 ) } ;
for ( int g = 0 ; g < ARRAY_COUNT ( attackable ) ; + + g )
{
if ( attackable [ g ] . first = = hex )
return attackable [ g ] . second ;
}
return - 1 ; //not found!
}
2010-04-06 16:19:54 +03:00
int BattleInfo : : lineToWallHex ( int line ) const
{
static const int lineToHex [ ] = { 12 , 29 , 45 , 62 , 78 , 95 , 112 , 130 , 147 , 165 , 182 } ;
return lineToHex [ line ] ;
}
2009-09-02 17:10:19 +03:00
std : : pair < const CStack * , int > BattleInfo : : getNearestStack ( const CStack * closest , boost : : logic : : tribool attackerOwned ) const
{
bool ac [ BFIELD_SIZE ] ;
std : : set < int > occupyable ;
2010-05-02 21:20:26 +03:00
getAccessibilityMap ( ac , closest - > doubleWide ( ) , closest - > attackerOwned , false , occupyable , closest - > hasBonusOfType ( Bonus : : FLYING ) , closest - > ID ) ;
2009-09-02 17:10:19 +03:00
int predecessor [ BFIELD_SIZE ] , dist [ BFIELD_SIZE ] ;
2010-05-02 21:20:26 +03:00
makeBFS ( closest - > position , ac , predecessor , dist , closest - > doubleWide ( ) , closest - > attackerOwned , closest - > hasBonusOfType ( Bonus : : FLYING ) , true ) ;
2009-09-02 17:10:19 +03:00
std : : vector < std : : pair < std : : pair < int , int > , const CStack * > > stackPairs ; //pairs <<distance, hex>, stack>
for ( int g = 0 ; g < BFIELD_SIZE ; + + g )
{
const CStack * atG = getStackT ( g ) ;
if ( ! atG | | atG - > ID = = closest - > ID ) //if there is not stack or we are the closest one
continue ;
if ( boost : : logic : : indeterminate ( attackerOwned ) | | atG - > attackerOwned = = attackerOwned )
{
if ( predecessor [ g ] = = - 1 ) //TODO: is it really the best solution?
continue ;
stackPairs . push_back ( std : : make_pair ( std : : make_pair ( dist [ predecessor [ g ] ] , g ) , atG ) ) ;
}
}
if ( stackPairs . size ( ) > 0 )
{
2009-09-06 20:46:20 +03:00
std : : vector < std : : pair < std : : pair < int , int > , const CStack * > > minimalPairs ;
minimalPairs . push_back ( stackPairs [ 0 ] ) ;
2009-09-02 17:10:19 +03:00
for ( int b = 1 ; b < stackPairs . size ( ) ; + + b )
{
2009-09-06 20:46:20 +03:00
if ( stackPairs [ b ] . first . first < minimalPairs [ 0 ] . first . first )
{
minimalPairs . clear ( ) ;
minimalPairs . push_back ( stackPairs [ b ] ) ;
}
else if ( stackPairs [ b ] . first . first = = minimalPairs [ 0 ] . first . first )
{
minimalPairs . push_back ( stackPairs [ b ] ) ;
}
2009-09-02 17:10:19 +03:00
}
2009-09-06 20:46:20 +03:00
std : : pair < std : : pair < int , int > , const CStack * > minPair = minimalPairs [ minimalPairs . size ( ) / 2 ] ;
return std : : make_pair ( minPair . second , predecessor [ minPair . first . second ] ) ;
2009-09-02 17:10:19 +03:00
}
return std : : make_pair < const CStack * , int > ( NULL , - 1 ) ;
}
2010-02-24 20:11:08 +02:00
ui32 BattleInfo : : calculateSpellDmg ( const CSpell * sp , const CGHeroInstance * caster , const CStack * affectedCreature , int spellSchoolLevel , int usedSpellPower ) const
2009-11-08 16:44:58 +02:00
{
ui32 ret = 0 ; //value to return
//15 - magic arrows, 16 - ice bolt, 17 - lightning bolt, 18 - implosion, 20 - frost ring, 21 - fireball, 22 - inferno, 23 - meteor shower,
2010-02-23 17:39:31 +02:00
//24 - death ripple, 25 - destroy undead, 26 - armageddon, 77 - thunderbolt
static std : : map < int , int > dmgMultipliers = boost : : assign : : map_list_of ( 15 , 10 ) ( 16 , 20 ) ( 17 , 25 ) ( 18 , 75 ) ( 20 , 10 ) ( 21 , 10 ) ( 22 , 10 ) ( 23 , 10 ) ( 24 , 5 ) ( 25 , 10 ) ( 26 , 50 ) ( 77 , 10 ) ;
2009-11-08 16:44:58 +02:00
//check if spell really does damage - if not, return 0
if ( dmgMultipliers . find ( sp - > id ) = = dmgMultipliers . end ( ) )
return 0 ;
2010-02-24 20:11:08 +02:00
ret = usedSpellPower * dmgMultipliers [ sp - > id ] ;
2010-02-23 17:39:31 +02:00
ret + = sp - > powers [ spellSchoolLevel ] ;
2009-11-08 16:44:58 +02:00
//applying sorcerery secondary skill
2010-02-23 17:39:31 +02:00
if ( caster )
2009-11-08 16:44:58 +02:00
{
2010-07-19 21:30:51 +03:00
ret * = ( 100.f + caster - > valOfBonuses ( Bonus : : SECONDARY_SKILL_PREMY , 25 ) ) / 100.0f ; //mysticism
2010-07-17 16:11:12 +03:00
ret * = ( 100.f + caster - > valOfBonuses ( Bonus : : SPELL_DAMAGE ) + caster - > valOfBonuses ( Bonus : : SPECIFIC_SPELL_DAMAGE , sp - > id ) ) / 100.0f ;
if ( sp - > air )
ret * = ( 100.0f + caster - > valOfBonuses ( Bonus : : AIR_SPELL_DMG_PREMY ) ) / 100.0f ;
else if ( sp - > fire ) //only one type of bonus for Magic Arrow
ret * = ( 100.0f + caster - > valOfBonuses ( Bonus : : FIRE_SPELL_DMG_PREMY ) ) / 100.0f ;
else if ( sp - > water )
ret * = ( 100.0f + caster - > valOfBonuses ( Bonus : : WATER_SPELL_DMG_PREMY ) ) / 100.0f ;
else if ( sp - > earth )
ret * = ( 100.0f + caster - > valOfBonuses ( Bonus : : EARTH_SPELL_DMG_PREMY ) ) / 100.0f ;
2009-11-08 16:44:58 +02:00
}
//affected creature-specific part
if ( affectedCreature )
{
//applying protections - when spell has more then one elements, only one protection should be applied (I think)
2010-05-02 21:20:26 +03:00
if ( sp - > air & & affectedCreature - > hasBonusOfType ( Bonus : : SPELL_DAMAGE_REDUCTION , 0 ) ) //air spell & protection from air
2009-11-08 16:44:58 +02:00
{
2010-05-02 21:20:26 +03:00
ret * = affectedCreature - > valOfBonuses ( Bonus : : SPELL_DAMAGE_REDUCTION , 0 ) ;
2009-11-08 16:44:58 +02:00
ret / = 100 ;
}
2010-05-02 21:20:26 +03:00
else if ( sp - > fire & & affectedCreature - > hasBonusOfType ( Bonus : : SPELL_DAMAGE_REDUCTION , 1 ) ) //fire spell & protection from fire
2009-11-08 16:44:58 +02:00
{
2010-05-02 21:20:26 +03:00
ret * = affectedCreature - > valOfBonuses ( Bonus : : SPELL_DAMAGE_REDUCTION , 1 ) ;
2009-11-08 16:44:58 +02:00
ret / = 100 ;
}
2010-05-02 21:20:26 +03:00
else if ( sp - > water & & affectedCreature - > hasBonusOfType ( Bonus : : SPELL_DAMAGE_REDUCTION , 2 ) ) //water spell & protection from water
2009-11-08 16:44:58 +02:00
{
2010-05-02 21:20:26 +03:00
ret * = affectedCreature - > valOfBonuses ( Bonus : : SPELL_DAMAGE_REDUCTION , 2 ) ;
2009-11-08 16:44:58 +02:00
ret / = 100 ;
}
2010-05-02 21:20:26 +03:00
else if ( sp - > earth & & affectedCreature - > hasBonusOfType ( Bonus : : SPELL_DAMAGE_REDUCTION , 3 ) ) //earth spell & protection from earth
2009-11-08 16:44:58 +02:00
{
2010-05-02 21:20:26 +03:00
ret * = affectedCreature - > valOfBonuses ( Bonus : : SPELL_DAMAGE_REDUCTION , 3 ) ;
2009-11-08 16:44:58 +02:00
ret / = 100 ;
}
//general spell dmg reduction
2010-05-02 21:20:26 +03:00
if ( sp - > air & & affectedCreature - > hasBonusOfType ( Bonus : : SPELL_DAMAGE_REDUCTION , - 1 ) ) //air spell & protection from air
2009-11-08 16:44:58 +02:00
{
2010-05-02 21:20:26 +03:00
ret * = affectedCreature - > valOfBonuses ( Bonus : : SPELL_DAMAGE_REDUCTION , - 1 ) ;
2009-11-08 16:44:58 +02:00
ret / = 100 ;
}
//dmg increasing
2010-05-02 21:20:26 +03:00
if ( affectedCreature - > hasBonusOfType ( Bonus : : MORE_DAMAGE_FROM_SPELL , sp - > id ) )
2009-11-08 16:44:58 +02:00
{
2010-05-02 21:20:26 +03:00
ret * = 100 + affectedCreature - > valOfBonuses ( Bonus : : MORE_DAMAGE_FROM_SPELL , sp - > id ) ;
2009-11-08 16:44:58 +02:00
ret / = 100 ;
}
2010-07-17 16:49:58 +03:00
if ( caster ) //Hero specials like Solmyr, Deemer
ret * = ( 100.f + ( ( caster - > valOfBonuses ( Bonus : : SPECIAL_SPELL_LEV , sp - > id ) * caster - > level ) / affectedCreature - > type - > level ) ) / 100.0f ;
2009-11-08 16:44:58 +02:00
}
return ret ;
}
2009-09-04 17:11:42 +03:00
bool CGameState : : battleCanShoot ( int ID , int dest )
{
if ( ! curB )
return false ;
const CStack * our = curB - > getStack ( ID ) ,
* dst = curB - > getStackT ( dest ) ;
if ( ! our | | ! dst ) return false ;
2009-09-05 17:10:26 +03:00
const CGHeroInstance * ourHero = battleGetOwner ( our - > ID ) ;
2009-09-04 17:11:42 +03:00
2010-05-02 21:20:26 +03:00
if ( our - > hasBonusOfType ( Bonus : : FORGETFULL ) ) //forgetfulness
2009-09-04 17:11:42 +03:00
return false ;
2010-05-02 21:20:26 +03:00
if ( our - > type - > idNumber = = 145 & & dst ) //catapult cannot attack creatures
2009-12-20 15:35:59 +02:00
return false ;
2010-05-02 21:20:26 +03:00
if ( our - > hasBonusOfType ( Bonus : : SHOOTER ) //it's shooter
2009-09-04 17:11:42 +03:00
& & our - > owner ! = dst - > owner
& & dst - > alive ( )
2010-05-02 21:20:26 +03:00
& & ( ! curB - > isStackBlocked ( ID ) | | NBonus : : hasOfType ( ourHero , Bonus : : FREE_SHOOTING ) )
2009-09-04 17:11:42 +03:00
& & our - > shots
)
return true ;
return false ;
}
2010-01-29 22:52:45 +02:00
int CGameState : : victoryCheck ( ui8 player ) const
{
const PlayerState * p = getPlayer ( player ) ;
if ( map - > victoryCondition . condition = = winStandard | | map - > victoryCondition . allowNormalVictory )
if ( player = = checkForStandardWin ( ) )
return - 1 ;
if ( p - > human | | map - > victoryCondition . appliesToAI )
{
switch ( map - > victoryCondition . condition )
{
case artifact :
//check if any hero has winning artifact
for ( size_t i = 0 ; i < p - > heroes . size ( ) ; i + + )
if ( p - > heroes [ i ] - > hasArt ( map - > victoryCondition . ID ) )
return 1 ;
break ;
case gatherTroop :
{
//check if in players armies there is enough creatures
int total = 0 ; //creature counter
for ( size_t i = 0 ; i < map - > objects . size ( ) ; i + + )
{
const CArmedInstance * ai = NULL ;
if ( map - > objects [ i ]
2010-01-30 14:46:15 +02:00
& & map - > objects [ i ] - > tempOwner = = player //object controlled by player
2010-01-29 22:52:45 +02:00
& & ( ai = dynamic_cast < const CArmedInstance * > ( map - > objects [ i ] ) ) ) //contains army
{
2010-05-02 21:20:26 +03:00
for ( TSlots : : const_iterator i = ai - > Slots ( ) . begin ( ) ; i ! = ai - > Slots ( ) . end ( ) ; + + i ) //iterate through army
2010-04-02 05:07:40 +03:00
if ( i - > second . type - > idNumber = = map - > victoryCondition . ID ) //it's searched creature
total + = i - > second . count ;
2010-01-29 22:52:45 +02:00
}
}
if ( total > = map - > victoryCondition . count )
return 1 ;
}
break ;
case gatherResource :
if ( p - > resources [ map - > victoryCondition . ID ] > = map - > victoryCondition . count )
return 1 ;
break ;
case buildCity :
2010-01-30 14:46:15 +02:00
{
const CGTownInstance * t = static_cast < const CGTownInstance * > ( map - > victoryCondition . obj ) ;
if ( t - > tempOwner = = player & & t - > fortLevel ( ) - 1 > = map - > victoryCondition . ID & & t - > hallLevel ( ) - 1 > = map - > victoryCondition . count )
2010-01-29 22:52:45 +02:00
return 1 ;
2010-01-30 14:46:15 +02:00
}
2010-01-29 22:52:45 +02:00
break ;
case buildGrail :
2010-05-14 05:18:37 +03:00
BOOST_FOREACH ( const CGTownInstance * t , map - > towns )
if ( ( t = = map - > victoryCondition . obj | | ! map - > victoryCondition . obj )
& & t - > tempOwner = = player
& & vstd : : contains ( t - > builtBuildings , 26 ) )
2010-01-29 22:52:45 +02:00
return 1 ;
break ;
case beatHero :
if ( map - > victoryCondition . obj - > tempOwner > = PLAYER_LIMIT ) //target hero not present on map
return 1 ;
break ;
case captureCity :
{
if ( map - > victoryCondition . obj - > tempOwner = = player )
return 1 ;
}
break ;
case beatMonster :
if ( ! map - > objects [ map - > victoryCondition . obj - > id ] ) //target monster not present on map
return 1 ;
break ;
case takeDwellings :
for ( size_t i = 0 ; i < map - > objects . size ( ) ; i + + )
{
if ( map - > objects [ i ] & & map - > objects [ i ] - > tempOwner ! = player ) //check not flagged objs
{
switch ( map - > objects [ i ] - > ID )
{
case 17 : case 18 : case 19 : case 20 : //dwellings
case 216 : case 217 : case 218 :
return 0 ; //found not flagged dwelling - player not won
}
}
}
return 1 ;
break ;
case takeMines :
for ( size_t i = 0 ; i < map - > objects . size ( ) ; i + + )
{
if ( map - > objects [ i ] & & map - > objects [ i ] - > tempOwner ! = player ) //check not flagged objs
{
switch ( map - > objects [ i ] - > ID )
{
case 53 : case 220 :
return 0 ; //found not flagged mine - player not won
}
}
}
return 1 ;
break ;
case transportItem :
2010-01-30 14:46:15 +02:00
{
const CGTownInstance * t = static_cast < const CGTownInstance * > ( map - > victoryCondition . obj ) ;
if ( t - > visitingHero & & t - > visitingHero - > hasArt ( map - > victoryCondition . ID )
| | t - > garrisonHero & & t - > garrisonHero - > hasArt ( map - > victoryCondition . ID ) )
{
return 1 ;
}
}
2010-01-29 22:52:45 +02:00
break ;
}
}
return 0 ;
}
ui8 CGameState : : checkForStandardWin ( ) const
{
//std victory condition is:
//all enemies lost
ui8 supposedWinner = 255 , winnerTeam = 255 ;
for ( std : : map < ui8 , PlayerState > : : const_iterator i = players . begin ( ) ; i ! = players . end ( ) ; i + + )
{
2010-01-30 17:00:05 +02:00
if ( i - > second . status = = PlayerState : : INGAME & & i - > first < PLAYER_LIMIT )
2010-01-29 22:52:45 +02:00
{
if ( supposedWinner = = 255 )
{
//first player remaining ingame - candidate for victory
supposedWinner = i - > second . color ;
winnerTeam = map - > players [ supposedWinner ] . team ;
}
else if ( winnerTeam ! = map - > players [ i - > second . color ] . team )
{
//current candidate has enemy remaining in game -> no vicotry
return 255 ;
}
}
}
return supposedWinner ;
}
bool CGameState : : checkForStandardLoss ( ui8 player ) const
{
//std loss condition is: player lost all towns and heroes
const PlayerState & p = * getPlayer ( player ) ;
2010-01-30 17:00:05 +02:00
return ! p . heroes . size ( ) & & ! p . towns . size ( ) ;
2010-01-29 22:52:45 +02:00
}
2010-02-11 21:18:30 +02:00
struct statsHLP
2010-02-01 19:51:33 +02:00
{
2010-02-11 21:18:30 +02:00
typedef std : : pair < ui8 , si64 > TStat ;
//converts [<player's color, value>] to vec[place] -> platers
static std : : vector < std : : list < ui8 > > getRank ( std : : vector < TStat > stats )
2010-02-01 19:51:33 +02:00
{
2010-02-11 21:18:30 +02:00
std : : sort ( stats . begin ( ) , stats . end ( ) , statsHLP ( ) ) ;
2010-02-01 19:51:33 +02:00
2010-02-11 21:18:30 +02:00
//put first element
std : : vector < std : : list < ui8 > > ret ;
std : : list < ui8 > tmp ;
tmp . push_back ( stats [ 0 ] . first ) ;
ret . push_back ( tmp ) ;
2010-02-01 19:51:33 +02:00
2010-02-11 21:18:30 +02:00
//the rest of elements
for ( int g = 1 ; g < stats . size ( ) ; + + g )
{
if ( stats [ g ] . second = = stats [ g - 1 ] . second )
2010-02-01 19:51:33 +02:00
{
2010-02-11 21:18:30 +02:00
( ret . end ( ) - 1 ) - > push_back ( stats [ g ] . first ) ;
}
else
{
//create next occupied rank
std : : list < ui8 > tmp ;
tmp . push_back ( stats [ g ] . first ) ;
ret . push_back ( tmp ) ;
2010-02-01 19:51:33 +02:00
}
}
2010-02-11 21:18:30 +02:00
return ret ;
}
2010-02-06 15:49:14 +02:00
2010-02-11 21:18:30 +02:00
bool operator ( ) ( const TStat & a , const TStat & b ) const
{
return a . second > b . second ;
}
static const CGHeroInstance * findBestHero ( CGameState * gs , int color )
{
2010-02-28 14:39:38 +02:00
std : : vector < CGHeroInstance * > & h = gs - > players [ color ] . heroes ;
if ( ! h . size ( ) )
return NULL ;
2010-02-11 21:18:30 +02:00
//best hero will be that with highest exp
int best = 0 ;
2010-02-28 14:39:38 +02:00
for ( int b = 1 ; b < h . size ( ) ; + + b )
2010-02-06 15:49:14 +02:00
{
2010-02-28 14:39:38 +02:00
if ( h [ b ] - > exp > h [ best ] - > exp )
2010-02-06 15:49:14 +02:00
{
2010-02-11 21:18:30 +02:00
best = b ;
2010-02-06 15:49:14 +02:00
}
}
2010-02-28 14:39:38 +02:00
return h [ best ] ;
2010-02-11 21:18:30 +02:00
}
2010-02-06 15:49:14 +02:00
2010-02-11 21:18:30 +02:00
//calculates total number of artifacts that belong to given player
static int getNumberOfArts ( const PlayerState * ps )
{
int ret = 0 ;
for ( int g = 0 ; g < ps - > heroes . size ( ) ; + + g )
2010-02-06 15:49:14 +02:00
{
2010-02-11 21:18:30 +02:00
ret + = ps - > heroes [ g ] - > artifacts . size ( ) + ps - > heroes [ g ] - > artifWorn . size ( ) ;
2010-02-06 15:49:14 +02:00
}
2010-02-11 21:18:30 +02:00
return ret ;
}
} ;
2010-02-01 19:51:33 +02:00
2010-02-11 21:18:30 +02:00
void CGameState : : obtainPlayersStats ( SThievesGuildInfo & tgi , int level )
{
2010-02-01 19:51:33 +02:00
# define FILL_FIELD(FIELD, VAL_GETTER) \
{ \
std : : vector < std : : pair < ui8 , si64 > > stats ; \
for ( std : : map < ui8 , PlayerState > : : const_iterator g = players . begin ( ) ; g ! = players . end ( ) ; + + g ) \
{ \
if ( g - > second . color = = 255 ) \
continue ; \
std : : pair < ui8 , si64 > stat ; \
stat . first = g - > second . color ; \
stat . second = VAL_GETTER ; \
stats . push_back ( stat ) ; \
} \
2010-02-11 21:18:30 +02:00
tgi . FIELD = statsHLP : : getRank ( stats ) ; \
2010-02-01 19:51:33 +02:00
}
for ( std : : map < ui8 , PlayerState > : : const_iterator g = players . begin ( ) ; g ! = players . end ( ) ; + + g )
{
if ( g - > second . color ! = 255 )
tgi . playerColors . push_back ( g - > second . color ) ;
}
if ( level > = 1 ) //num of towns & num of heroes
{
//num of towns
FILL_FIELD ( numOfTowns , g - > second . towns . size ( ) )
//num of heroes
FILL_FIELD ( numOfHeroes , g - > second . heroes . size ( ) )
2010-02-04 20:40:40 +02:00
//best hero's portrait
for ( std : : map < ui8 , PlayerState > : : const_iterator g = players . begin ( ) ; g ! = players . end ( ) ; + + g )
{
if ( g - > second . color = = 255 )
continue ;
2010-02-11 21:18:30 +02:00
const CGHeroInstance * best = statsHLP : : findBestHero ( this , g - > second . color ) ;
2010-02-07 17:06:14 +02:00
InfoAboutHero iah ;
iah . initFromHero ( best , level > = 8 ) ;
2010-05-02 21:20:26 +03:00
iah . army . clear ( ) ;
2010-02-04 20:40:40 +02:00
tgi . colorToBestHero [ g - > second . color ] = iah ;
}
2010-02-01 19:51:33 +02:00
}
if ( level > = 2 ) //gold
{
FILL_FIELD ( gold , g - > second . resources [ 6 ] )
}
if ( level > = 2 ) //wood & ore
{
FILL_FIELD ( woodOre , g - > second . resources [ 0 ] + g - > second . resources [ 1 ] )
}
if ( level > = 3 ) //mercury, sulfur, crystal, gems
{
2010-02-06 15:49:14 +02:00
FILL_FIELD ( mercSulfCrystGems , g - > second . resources [ 2 ] + g - > second . resources [ 3 ] + g - > second . resources [ 4 ] + g - > second . resources [ 5 ] )
2010-02-01 19:51:33 +02:00
}
if ( level > = 4 ) //obelisks found
{
//TODO
}
if ( level > = 5 ) //artifacts
{
2010-02-11 21:18:30 +02:00
FILL_FIELD ( artifacts , statsHLP : : getNumberOfArts ( & g - > second ) )
2010-02-01 19:51:33 +02:00
}
if ( level > = 6 ) //army strength
{
//TODO
}
if ( level > = 7 ) //income
{
//TODO
}
2010-02-06 15:49:14 +02:00
if ( level > = 8 ) //best hero's stats
{
2010-02-07 17:06:14 +02:00
//already set in lvl 1 handling
2010-02-06 15:49:14 +02:00
}
if ( level > = 9 ) //personality
{
for ( std : : map < ui8 , PlayerState > : : const_iterator g = players . begin ( ) ; g ! = players . end ( ) ; + + g )
{
if ( g - > second . color = = 255 ) //do nothing for neutral player
continue ;
if ( g - > second . human )
{
tgi . personality [ g - > second . color ] = - 1 ;
}
else //AI
{
tgi . personality [ g - > second . color ] = map - > players [ g - > second . serial ] . AITactic ;
}
}
}
if ( level > = 10 ) //best creature
{
//best creatures belonging to player (highest AI value)
for ( std : : map < ui8 , PlayerState > : : const_iterator g = players . begin ( ) ; g ! = players . end ( ) ; + + g )
{
if ( g - > second . color = = 255 ) //do nothing for neutral player
continue ;
int bestCre = - 1 ; //best creature's ID
for ( int b = 0 ; b < g - > second . heroes . size ( ) ; + + b )
{
2010-05-02 21:20:26 +03:00
for ( TSlots : : const_iterator it = g - > second . heroes [ b ] - > Slots ( ) . begin ( ) ; it ! = g - > second . heroes [ b ] - > Slots ( ) . end ( ) ; + + it )
2010-02-06 15:49:14 +02:00
{
2010-04-02 05:07:40 +03:00
int toCmp = it - > second . type - > idNumber ; //ID of creature we should compare with the best one
2010-05-02 21:20:26 +03:00
if ( bestCre = = - 1 | | VLC - > creh - > creatures [ bestCre ] - > AIValue < VLC - > creh - > creatures [ toCmp ] - > AIValue )
2010-02-06 15:49:14 +02:00
{
bestCre = toCmp ;
}
}
}
tgi . bestCreature [ g - > second . color ] = bestCre ;
}
}
2010-02-01 19:51:33 +02:00
# undef FILL_FIELD
}
2010-01-29 22:52:45 +02:00
int CGameState : : lossCheck ( ui8 player ) const
{
const PlayerState * p = 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 ;
if ( p - > human ) //special loss condition applies only to human player
{
switch ( map - > lossCondition . typeOfLossCon )
{
case lossCastle :
{
const CGTownInstance * t = dynamic_cast < const CGTownInstance * > ( map - > lossCondition . obj ) ;
assert ( t ) ;
if ( t - > tempOwner ! = player )
return 1 ;
}
break ;
case lossHero :
{
const CGHeroInstance * h = dynamic_cast < const CGHeroInstance * > ( map - > lossCondition . obj ) ;
assert ( h ) ;
if ( h - > tempOwner ! = player )
return 1 ;
}
break ;
case timeExpires :
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-07-08 08:52:11 +03:00
std : : map < ui32 , CGHeroInstance * > CGameState : : unusedHeroesFromPool ( )
{
std : : map < ui32 , CGHeroInstance * > pool = hpool . heroesPool ;
for ( std : : map < ui8 , PlayerState > : : iterator i = players . begin ( ) ; i ! = players . end ( ) ; i + + )
for ( std : : vector < CGHeroInstance * > : : iterator j = i - > second . availableHeroes . begin ( ) ; j ! = i - > second . availableHeroes . end ( ) ; j + + )
if ( * j )
pool . erase ( ( * * j ) . subID ) ;
return pool ;
}
2009-09-07 05:29:44 +03:00
const CStack * BattleInfo : : getNextStack ( ) const
2008-11-15 17:26:08 +02:00
{
2009-09-07 05:29:44 +03:00
std : : vector < const CStack * > hlp ;
2009-09-20 15:47:40 +03:00
getStackQueue ( hlp , 1 , - 1 ) ;
2009-09-07 05:29:44 +03:00
if ( hlp . size ( ) )
return hlp [ 0 ] ;
else
return NULL ;
}
2009-09-20 15:47:40 +03:00
static const CStack * takeStack ( std : : vector < const CStack * > & st , int & curside , int turn )
2009-09-07 05:29:44 +03:00
{
const CStack * ret = NULL ;
unsigned i , //fastest stack
j ; //fastest stack of the other side
for ( i = 0 ; i < st . size ( ) ; i + + )
if ( st [ i ] )
break ;
//no stacks left
if ( i = = st . size ( ) )
return NULL ;
const CStack * fastest = st [ i ] , * other = NULL ;
2009-09-20 15:47:40 +03:00
int bestSpeed = fastest - > Speed ( turn ) ;
2009-09-07 05:29:44 +03:00
if ( fastest - > attackerOwned ! = curside )
2008-11-15 17:26:08 +02:00
{
2009-09-07 05:29:44 +03:00
ret = fastest ;
2008-11-15 17:26:08 +02:00
}
2009-09-07 05:29:44 +03:00
else
2008-11-15 17:26:08 +02:00
{
2009-09-07 05:29:44 +03:00
for ( j = i + 1 ; j < st . size ( ) ; j + + )
{
if ( ! st [ j ] ) continue ;
2009-09-20 15:47:40 +03:00
if ( st [ j ] - > attackerOwned ! = curside | | st [ j ] - > Speed ( turn ) ! = bestSpeed )
2009-09-07 05:29:44 +03:00
break ;
}
if ( j > = st . size ( ) )
{
ret = fastest ;
}
else
{
other = st [ j ] ;
2009-09-20 15:47:40 +03:00
if ( other - > Speed ( turn ) ! = bestSpeed )
2009-09-07 05:29:44 +03:00
ret = fastest ;
else
ret = other ;
}
2008-11-15 17:26:08 +02:00
}
2009-09-07 05:29:44 +03:00
assert ( ret ) ;
if ( ret = = fastest )
st [ i ] = NULL ;
else
st [ j ] = NULL ;
curside = ret - > attackerOwned ;
return ret ;
2008-12-20 19:08:51 +02:00
}
2009-09-20 15:47:40 +03:00
void BattleInfo : : getStackQueue ( std : : vector < const CStack * > & out , int howMany , int turn /*= 0*/ , int lastMoved /*= -1*/ ) const
2008-12-20 19:08:51 +02:00
{
2009-09-07 05:29:44 +03:00
//we'll split creatures with remaining movement to 4 parts
std : : vector < const CStack * > phase [ 4 ] ; //0 - turrets/catapult, 1 - normal (unmoved) creatures, other war machines, 2 - waited cres that had morale, 3 - rest of waited cres
int toMove = 0 ; //how many stacks still has move
2009-09-20 15:47:40 +03:00
const CStack * active = getStack ( activeStack ) ;
//active stack hasn't taken any action yet - must be placed at the beginning of queue, no matter what
if ( ! turn & & active & & active - > willMove ( ) & & ! vstd : : contains ( active - > state , WAITING ) )
{
out . push_back ( active ) ;
if ( out . size ( ) = = howMany )
return ;
}
2008-12-20 19:08:51 +02:00
2009-09-07 05:29:44 +03:00
for ( unsigned int i = 0 ; i < stacks . size ( ) ; + + i )
2008-12-20 19:08:51 +02:00
{
2009-09-07 05:29:44 +03:00
const CStack * const s = stacks [ i ] ;
2009-09-20 15:47:40 +03:00
if ( turn < = 0 & & ! s - > willMove ( ) //we are considering current round and stack won't move
| | turn > 0 & & ! s - > canMove ( turn ) //stack won't be able to move in later rounds
2009-11-21 00:35:18 +02:00
| | turn < = 0 & & s = = active & & out . size ( ) & & s = = out . front ( ) ) //it's active stack already added at the beginning of queue
2008-12-20 19:08:51 +02:00
{
2009-09-20 15:47:40 +03:00
continue ;
}
2009-09-07 05:29:44 +03:00
2009-09-20 15:47:40 +03:00
int p = - 1 ; //in which phase this tack will move?
if ( turn < = 0 & & vstd : : contains ( s - > state , WAITING ) ) //consider waiting state only for ongoing round
{
if ( vstd : : contains ( s - > state , HAD_MORALE ) )
p = 2 ;
else
p = 3 ;
2009-09-07 05:29:44 +03:00
}
2010-05-02 21:20:26 +03:00
else if ( s - > type - > idNumber = = 145 | | s - > type - > idNumber = = 149 ) //catapult and turrets are first
2009-09-20 15:47:40 +03:00
{
p = 0 ;
}
else
{
p = 1 ;
}
phase [ p ] . push_back ( s ) ;
toMove + + ;
2009-09-07 05:29:44 +03:00
}
for ( int i = 0 ; i < 4 ; i + + )
2009-09-20 15:47:40 +03:00
std : : sort ( phase [ i ] . begin ( ) , phase [ i ] . end ( ) , CMP_stack ( i , turn > 0 ? turn : 0 ) ) ;
2009-09-07 05:29:44 +03:00
for ( size_t i = 0 ; i < phase [ 0 ] . size ( ) & & i < howMany ; i + + )
out . push_back ( phase [ 0 ] [ i ] ) ;
if ( out . size ( ) = = howMany )
return ;
if ( lastMoved = = - 1 )
{
2009-09-20 15:47:40 +03:00
if ( active )
2009-09-07 05:29:44 +03:00
{
2009-09-20 15:47:40 +03:00
if ( out . size ( ) & & out . front ( ) = = active )
lastMoved = active - > attackerOwned ;
else
lastMoved = active - > attackerOwned ;
2009-09-07 05:29:44 +03:00
}
else
{
lastMoved = 0 ;
}
}
int pi = 1 ;
while ( out . size ( ) < howMany )
{
2009-09-20 15:47:40 +03:00
const CStack * hlp = takeStack ( phase [ pi ] , lastMoved , turn ) ;
2009-09-07 05:29:44 +03:00
if ( ! hlp )
{
pi + + ;
if ( pi > 3 )
{
2009-09-20 15:47:40 +03:00
//if(turn != 2)
getStackQueue ( out , howMany , turn + 1 , lastMoved ) ;
2009-09-07 05:29:44 +03:00
return ;
}
}
else
{
out . push_back ( hlp ) ;
2008-12-20 19:08:51 +02:00
}
}
}
2009-03-19 16:17:19 +02:00
2010-04-06 16:19:54 +03:00
si8 BattleInfo : : hasDistancePenalty ( int stackID , int destHex )
{
const CStack * stack = getStack ( stackID ) ;
2010-07-28 15:31:34 +03:00
struct HLP
{
static bool lowerAnalyze ( const CStack * stack , int hex )
{
2010-07-29 15:54:30 +03:00
int distance = BattleInfo : : getDistance ( hex , stack - > position ) ;
2010-07-28 15:31:34 +03:00
//I hope it's approximately correct
return distance > 10 & & ! stack - > hasBonusOfType ( Bonus : : NO_DISTANCE_PENALTY ) ;
}
} ;
const CStack * dstStack = getStackT ( destHex , false ) ;
2010-04-06 16:19:54 +03:00
2010-07-28 15:31:34 +03:00
if ( dstStack - > doubleWide ( ) )
return HLP : : lowerAnalyze ( stack , destHex ) & & HLP : : lowerAnalyze ( stack , dstStack - > occupiedHex ( ) ) ;
else
return HLP : : lowerAnalyze ( stack , destHex ) ;
2010-04-06 16:19:54 +03:00
}
2010-05-07 17:05:48 +03:00
si8 BattleInfo : : sameSideOfWall ( int pos1 , int pos2 )
{
int wallInStackLine = lineToWallHex ( pos1 / BFIELD_WIDTH ) ;
int wallInDestLine = lineToWallHex ( pos2 / BFIELD_WIDTH ) ;
bool stackLeft = pos1 < wallInStackLine ;
bool destLeft = pos2 < wallInDestLine ;
return stackLeft ! = destLeft ;
}
2010-04-06 16:19:54 +03:00
si8 BattleInfo : : hasWallPenalty ( int stackID , int destHex )
{
if ( siege = = 0 )
{
return false ;
}
const CStack * stack = getStack ( stackID ) ;
2010-05-02 21:20:26 +03:00
if ( stack - > hasBonusOfType ( Bonus : : NO_WALL_PENALTY ) ) ;
2010-04-06 16:19:54 +03:00
{
return false ;
}
2010-05-07 17:05:48 +03:00
return ! sameSideOfWall ( stack - > position , destHex ) ;
}
si8 BattleInfo : : canTeleportTo ( int stackID , int destHex , int telportLevel )
{
bool ac [ BFIELD_SIZE ] ;
const CStack * s = getStack ( stackID , false ) ; //this function is called from healedOrResurrected, so our stack can be dead
std : : set < int > occupyable ;
getAccessibilityMap ( ac , s - > doubleWide ( ) , s - > attackerOwned , false , occupyable , s - > hasBonusOfType ( Bonus : : FLYING ) , stackID ) ;
if ( siege & & telportLevel < 2 ) //check for wall
{
return ac [ destHex ] & & sameSideOfWall ( s - > position , destHex ) ;
}
else
{
return ac [ destHex ] ;
}
2010-04-06 16:19:54 +03:00
}
2010-05-02 21:20:26 +03:00
void BattleInfo : : getBonuses ( BonusList & out , const CSelector & selector , const CBonusSystemNode * root /*= NULL*/ ) const
{
CBonusSystemNode : : getBonuses ( out , selector , root ) ;
const CStack * dest = dynamic_cast < const CStack * > ( root ) ;
if ( ! dest )
return ;
//TODO: make it in clean way
if ( Selector : : matchesType ( selector , Bonus : : MORALE ) | | Selector : : matchesType ( selector , Bonus : : LUCK ) )
{
BOOST_FOREACH ( const CStack * s , stacks )
{
if ( s - > owner = = dest - > owner )
s - > getBonuses ( out , selector , Selector : : effectRange ( Bonus : : ONLY_ALLIED_ARMY ) , this ) ;
else
s - > getBonuses ( out , selector , Selector : : effectRange ( Bonus : : ONLY_ENEMY_ARMY ) , this ) ;
}
}
}
2010-07-29 15:54:30 +03:00
si8 BattleInfo : : getDistance ( int hex1 , int hex2 )
{
int xDst = std : : abs ( hex1 % BFIELD_WIDTH - hex2 % BFIELD_WIDTH ) ,
yDst = std : : abs ( hex1 / BFIELD_WIDTH - hex2 / BFIELD_WIDTH ) ;
return std : : max ( xDst , yDst ) + std : : min ( xDst , yDst ) - ( yDst + 1 ) / 2 ;
}
2009-03-19 21:04:46 +02:00
int3 CPath : : startPos ( ) const
2009-03-19 16:17:19 +02:00
{
2009-03-19 21:04:46 +02:00
return nodes [ nodes . size ( ) - 1 ] . coord ;
2009-03-19 16:17:19 +02:00
}
void CPath : : convert ( ui8 mode ) //mode=0 -> from 'manifest' to 'object'
{
if ( mode = = 0 )
{
2009-05-07 08:01:45 +03:00
for ( unsigned int i = 0 ; i < nodes . size ( ) ; i + + )
2009-03-19 16:17:19 +02:00
{
nodes [ i ] . coord = CGHeroInstance : : convertPosition ( nodes [ i ] . coord , true ) ;
}
}
}
2009-03-19 21:04:46 +02:00
int3 CPath : : endPos ( ) const
2009-03-19 16:17:19 +02:00
{
2009-03-19 21:04:46 +02:00
return nodes [ 0 ] . coord ;
2009-03-19 16:17:19 +02:00
}
2009-08-30 15:47:40 +03:00
CGPathNode : : CGPathNode ( )
: coord ( - 1 , - 1 , - 1 )
{
accessible = 0 ;
land = 0 ;
moveRemains = 0 ;
turns = 255 ;
theNodeBefore = NULL ;
}
bool CPathsInfo : : getPath ( const int3 & dst , CGPath & out )
{
out . nodes . clear ( ) ;
const CGPathNode * curnode = & nodes [ dst . x ] [ dst . y ] [ dst . z ] ;
2010-05-15 18:00:19 +03:00
if ( ! curnode - > theNodeBefore | | curnode - > accessible = = CGPathNode : : FLYABLE )
2009-08-30 15:47:40 +03:00
return false ;
2010-05-15 18:00:19 +03:00
//we'll transform number of turns to conform the rule that hero cannot stop on blocked tile
bool transition01 = false ;
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 ;
if ( transition01 )
{
if ( curnode - > accessible = = CGPathNode : : ACCESSIBLE )
{
transition01 = false ;
}
else if ( curnode - > accessible = = CGPathNode : : FLYABLE )
{
cpn . turns = 1 ;
}
}
if ( curnode - > turns = = 1 & & curnode - > theNodeBefore - > turns = = 0 )
{
transition01 = true ;
}
2009-08-30 15:47:40 +03:00
curnode = curnode - > theNodeBefore ;
2010-05-15 18:00:19 +03:00
out . nodes . push_back ( cpn ) ;
2009-08-30 15:47:40 +03:00
}
return true ;
}
CPathsInfo : : CPathsInfo ( const int3 & Sizes )
: sizes ( Sizes )
{
2009-11-13 18:02:25 +02:00
hero = NULL ;
2009-08-30 15:47:40 +03:00
nodes = new CGPathNode * * [ sizes . x ] ;
for ( int i = 0 ; i < sizes . x ; i + + )
{
nodes [ i ] = new CGPathNode * [ sizes . y ] ;
for ( int j = 0 ; j < sizes . y ; j + + )
{
nodes [ i ] [ j ] = new CGPathNode [ sizes . z ] ;
}
}
}
CPathsInfo : : ~ CPathsInfo ( )
{
for ( int i = 0 ; i < sizes . x ; i + + )
{
for ( int j = 0 ; j < sizes . y ; j + + )
{
delete [ ] nodes [ i ] [ j ] ;
}
delete [ ] nodes [ i ] ;
}
delete [ ] nodes ;
2009-09-07 05:29:44 +03:00
}
int3 CGPath : : startPos ( ) const
{
return nodes [ nodes . size ( ) - 1 ] . coord ;
}
int3 CGPath : : endPos ( ) const
{
return nodes [ 0 ] . coord ;
}
void CGPath : : convert ( ui8 mode )
{
if ( mode = = 0 )
{
for ( unsigned int i = 0 ; i < nodes . size ( ) ; i + + )
{
nodes [ i ] . coord = CGHeroInstance : : convertPosition ( nodes [ i ] . coord , true ) ;
}
}
}
bool CMP_stack : : operator ( ) ( const CStack * a , const CStack * b )
{
switch ( phase )
{
case 0 : //catapult moves after turrets
2010-05-02 21:20:26 +03:00
return a - > type - > idNumber < b - > type - > idNumber ; //catapult is 145 and turrets are 149
2009-09-07 05:29:44 +03:00
//TODO? turrets order
case 1 : //fastest first, upper slot first
{
2009-09-20 15:47:40 +03:00
int as = a - > Speed ( turn ) , bs = b - > Speed ( turn ) ;
2009-09-07 05:29:44 +03:00
if ( as ! = bs )
return as > bs ;
else
return a - > slot < b - > slot ;
}
case 2 : //fastest last, upper slot first
//TODO: should be replaced with order of receiving morale!
case 3 : //fastest last, upper slot first
{
2009-09-20 15:47:40 +03:00
int as = a - > Speed ( turn ) , bs = b - > Speed ( turn ) ;
2009-09-07 05:29:44 +03:00
if ( as ! = bs )
return as < bs ;
else
return a - > slot < b - > slot ;
}
default :
assert ( 0 ) ;
return false ;
}
}
2009-09-20 15:47:40 +03:00
CMP_stack : : CMP_stack ( int Phase /*= 1*/ , int Turn )
2009-09-07 05:29:44 +03:00
{
phase = Phase ;
2009-09-20 15:47:40 +03:00
turn = Turn ;
2009-09-07 05:29:44 +03:00
}
PlayerState : : PlayerState ( )
2010-01-29 22:52:45 +02:00
: color ( - 1 ) , currentSelection ( 0xffffffff ) , status ( INGAME ) , daysWithoutCastle ( 0 )
2009-09-07 05:29:44 +03:00
{
2009-10-04 05:02:45 +03:00
}
2010-02-07 17:06:14 +02:00
2010-05-02 21:20:26 +03:00
void PlayerState : : getParents ( TCNodes & out , const CBonusSystemNode * root /*= NULL*/ ) const
{
2010-06-28 08:07:21 +03:00
/*
for ( std : : vector < CGHeroInstance * > : : const_iterator it = heroes . begin ( ) ; it ! = heroes . end ( ) ; + + it )
{
if ( * it ! = root )
( * it ) - > getParents ( out , root ) ;
}
for ( std : : vector < CGTownInstance * > : : const_iterator it = towns . begin ( ) ; it ! = towns . end ( ) ; + + it )
{
if ( * it ! = root )
( * it ) - > getParents ( out , root ) ;
}
*/
//TODO - dwellings
2010-05-02 21:20:26 +03:00
}
2010-05-14 05:18:37 +03:00
void PlayerState : : getBonuses ( BonusList & out , const CSelector & selector , const CBonusSystemNode * root /*= NULL*/ ) const
2010-06-28 08:07:21 +03:00
{ //temporary
//CBonusSystemNode::getBonuses(out, selector, root);
2010-05-14 05:18:37 +03:00
}
2010-02-07 17:06:14 +02:00
InfoAboutHero : : InfoAboutHero ( )
{
details = NULL ;
hclass = NULL ;
portrait = - 1 ;
}
2010-02-07 19:56:06 +02:00
InfoAboutHero : : InfoAboutHero ( const InfoAboutHero & iah )
{
assign ( iah ) ;
}
2010-02-07 17:06:14 +02:00
InfoAboutHero : : ~ InfoAboutHero ( )
{
delete details ;
}
void InfoAboutHero : : initFromHero ( const CGHeroInstance * h , bool detailed )
{
2010-02-28 14:39:38 +02:00
if ( ! h ) return ;
2010-02-07 17:06:14 +02:00
owner = h - > tempOwner ;
hclass = h - > type - > heroClass ;
name = h - > name ;
portrait = h - > portrait ;
2010-05-02 21:20:26 +03:00
army = h - > getArmy ( ) ;
2010-02-07 17:06:14 +02:00
if ( detailed )
{
//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 ;
details - > primskills . resize ( PRIMARY_SKILLS ) ;
for ( int i = 0 ; i < PRIMARY_SKILLS ; i + + )
{
details - > primskills [ i ] = h - > getPrimSkillLevel ( i ) ;
}
}
else
{
//hide info about hero stacks counts using descriptives names ids
2010-05-02 21:20:26 +03:00
for ( TSlots : : const_iterator i = army . Slots ( ) . begin ( ) ; i ! = army . Slots ( ) . end ( ) ; + + i )
2010-02-07 17:06:14 +02:00
{
2010-05-26 12:47:53 +03:00
army . setStackCount ( i - > first , i - > second . getQuantityID ( ) + 1 ) ;
2010-02-07 17:06:14 +02:00
}
}
}
2010-02-07 19:56:06 +02:00
void InfoAboutHero : : assign ( const InfoAboutHero & iah )
{
army = iah . army ;
details = ( iah . details ? new Details ( * iah . details ) : NULL ) ;
hclass = iah . hclass ;
name = iah . name ;
owner = iah . owner ;
portrait = iah . portrait ;
}
InfoAboutHero & InfoAboutHero : : operator = ( const InfoAboutHero & iah )
{
assign ( iah ) ;
return * this ;
2010-02-13 17:56:34 +02:00
}
2010-05-08 21:56:38 +03:00
void CCampaignState : : initNewCampaign ( const StartInfo & si )
{
assert ( si . mode = = 2 ) ;
campaignName = si . mapname ;
currentMap = si . whichMapInCampaign ;
camp = CCampaignHandler : : getCampaign ( campaignName , true ) ; //TODO lod???
for ( ui8 i = 0 ; i < camp - > mapPieces . size ( ) ; i + + )
mapsRemaining . push_back ( i ) ;
}