2008-06-30 03:06:41 +03:00
# define VCMI_DLL
# 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"
# 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"
2009-07-09 22:15:22 +03:00
2008-06-30 03:06:41 +03:00
boost : : rand48 ran ;
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 ;
} ;
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 ) ;
}
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 ( )
{
T : : preInit ( ) ;
}
void postInit ( )
{
T : : postInit ( ) ;
}
} ;
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 ( )
{
for ( size_t i = 0 ; i < apps . size ( ) ; i + + )
apps [ i ] - > preInit ( ) ;
}
void postInit ( )
{
for ( size_t i = 0 ; i < apps . size ( ) ; i + + )
apps [ i ] - > postInit ( ) ;
}
} * 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 )
{
dst = VLC - > arth - > artifacts [ ser ] . Name ( ) ;
}
else if ( type = = CRE_PL_NAMES )
{
dst = VLC - > creh - > creatures [ ser ] . namePl ;
}
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 )
{
dst = VLC - > creh - > creatures [ ser ] . nameSing ;
}
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 ;
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
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 ;
}
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 - > info = NULL ;
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
2009-08-05 15:46:08 +03:00
| | ( stacks [ g ] - > hasFeatureOfType ( StackFeature : : DOUBLE_WIDE ) & & stacks [ g ] - > attackerOwned & & stacks [ g ] - > position - 1 = = tileID )
| | ( stacks [ g ] - > hasFeatureOfType ( StackFeature : : DOUBLE_WIDE ) & & ! 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 ;
2009-08-05 15:46:08 +03:00
if ( stacks [ g ] - > hasFeatureOfType ( StackFeature : : DOUBLE_WIDE ) ) //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 ;
2009-08-05 15:46:08 +03:00
getAccessibilityMap ( ac , s - > hasFeatureOfType ( StackFeature : : DOUBLE_WIDE ) , s - > attackerOwned , addOccupiable , occupyable , s - > hasFeatureOfType ( StackFeature : : 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 ] ;
2009-09-06 20:46:20 +03:00
makeBFS ( s - > position , ac , pr , dist , s - > hasFeatureOfType ( StackFeature : : DOUBLE_WIDE ) , s - > attackerOwned , s - > hasFeatureOfType ( StackFeature : : FLYING ) , false ) ;
2009-02-14 15:49:30 +02:00
2009-08-05 15:46:08 +03:00
if ( s - > hasFeatureOfType ( StackFeature : : DOUBLE_WIDE ) )
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 (
2009-08-05 15:46:08 +03:00
( ( ! addOccupiable & & dist [ i ] < = s - > Speed ( ) & & ac [ i ] ) | | ( addOccupiable & & dist [ i ] < = s - > Speed ( ) & & isAccessible ( i , ac , s - > hasFeatureOfType ( StackFeature : : DOUBLE_WIDE ) , s - > attackerOwned , s - > hasFeatureOfType ( StackFeature : : 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 ) ;
2009-08-07 12:45:21 +03:00
if ( our - > hasFeatureOfType ( StackFeature : : 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
2009-08-05 15:46:08 +03:00
if ( stacks [ i ] - > hasFeatureOfType ( StackFeature : : DOUBLE_WIDE ) )
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
}
2009-09-20 15:47:40 +03:00
int CStack : : valOfFeatures ( StackFeature : : ECombatFeatures type , int subtype , int turn ) const
2009-05-08 19:55:04 +03:00
{
int ret = 0 ;
2009-05-24 20:35:11 +03:00
if ( subtype = = - 1024 ) //any subtype
2009-05-08 19:55:04 +03:00
{
for ( std : : vector < StackFeature > : : const_iterator i = features . begin ( ) ; i ! = features . end ( ) ; i + + )
2009-09-20 15:47:40 +03:00
if ( i - > type = = type & & ( ! turn | | i - > turnsRemain > turn ) )
2009-05-08 19:55:04 +03:00
ret + = i - > value ;
}
2009-05-24 20:35:11 +03:00
else //given subtype
2009-05-08 19:55:04 +03:00
{
for ( std : : vector < StackFeature > : : const_iterator i = features . begin ( ) ; i ! = features . end ( ) ; i + + )
2009-09-20 15:47:40 +03:00
if ( i - > type = = type & & i - > subtype = = subtype & & ( ! turn | | i - > turnsRemain > turn ) )
2009-05-08 19:55:04 +03:00
ret + = i - > value ;
}
return ret ;
}
2009-09-20 15:47:40 +03:00
bool CStack : : hasFeatureOfType ( StackFeature : : ECombatFeatures type , int subtype , int turn ) const
2009-05-08 19:55:04 +03:00
{
2009-05-24 20:35:11 +03:00
if ( subtype = = - 1024 ) //any subtype
2009-05-08 19:55:04 +03:00
{
for ( std : : vector < StackFeature > : : const_iterator i = features . begin ( ) ; i ! = features . end ( ) ; i + + )
2009-09-20 15:47:40 +03:00
if ( i - > type = = type & & ( ! turn | | i - > turnsRemain > turn ) )
2009-05-08 19:55:04 +03:00
return true ;
}
else //given subtype
{
for ( std : : vector < StackFeature > : : const_iterator i = features . begin ( ) ; i ! = features . end ( ) ; i + + )
2009-09-20 15:47:40 +03:00
if ( i - > type = = type & & i - > subtype = = subtype & & ( ! turn | | i - > turnsRemain > turn ) )
2009-05-08 19:55:04 +03:00
return true ;
}
return false ;
}
2008-09-09 10:05:02 +03:00
CStack : : CStack ( CCreature * C , int A , int O , int I , bool AO , int S )
2009-04-15 13:20:47 +03:00
: ID ( I ) , creature ( C ) , amount ( A ) , baseAmount ( A ) , firstHPleft ( C - > hitPoints ) , owner ( O ) , slot ( S ) , attackerOwned ( AO ) , position ( - 1 ) ,
2009-05-17 18:24:50 +03:00
counterAttacks ( 1 ) , shots ( C - > shots ) , features ( C - > abilities )
2008-06-30 03:06:41 +03:00
{
2009-08-17 14:22:29 +03:00
//additional retaliations
for ( int h = 0 ; h < C - > abilities . size ( ) ; + + h )
{
if ( C - > abilities [ h ] . type = = StackFeature : : ADDITIONAL_RETALIATION )
{
counterAttacks + = C - > abilities [ h ] . value ;
}
}
//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
{
2009-09-20 15:47:40 +03:00
if ( hasFeatureOfType ( StackFeature : : SIEGE_WEAPON , - 1024 , turn ) ) //war machnes cannot move
2009-07-26 15:15:38 +03:00
return 0 ;
2009-05-17 18:24:50 +03:00
int speed = creature - > speed ;
2009-09-20 15:47:40 +03:00
speed + = valOfFeatures ( StackFeature : : SPEED_BONUS , - 1024 , turn ) ;
2009-05-17 18:24:50 +03:00
int percentBonus = 0 ;
for ( int g = 0 ; g < features . size ( ) ; + + g )
{
2009-10-17 17:53:16 +03:00
if ( features [ g ] . type = = StackFeature : : SPEED_BONUS )
2009-05-17 18:24:50 +03:00
{
percentBonus + = features [ g ] . additionalInfo ;
}
}
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-02-05 11:49:45 +02:00
si8 CStack : : Morale ( ) const
{
si8 ret = morale ;
2009-06-30 15:28:22 +03:00
2009-07-22 12:31:20 +03:00
if ( hasFeatureOfType ( StackFeature : : NON_LIVING ) | | hasFeatureOfType ( StackFeature : : UNDEAD ) | | hasFeatureOfType ( StackFeature : : NO_MORALE ) )
2009-06-30 15:28:22 +03:00
return 0 ;
2009-05-24 20:35:11 +03:00
ret + = valOfFeatures ( StackFeature : : MORALE_BONUS ) ; //mirth & sorrow & other
if ( hasFeatureOfType ( StackFeature : : SELF_MORALE ) ) //eg. minotaur
2009-02-06 13:50:48 +02:00
{
2009-05-24 20:35:11 +03:00
ret = std : : max < si8 > ( ret , + 1 ) ;
2009-02-06 13:50:48 +02:00
}
2009-05-24 20:35:11 +03:00
2009-02-06 13:50:48 +02:00
if ( ret > 3 ) ret = 3 ;
if ( ret < - 3 ) ret = - 3 ;
2009-02-05 11:49:45 +02:00
return ret ;
}
si8 CStack : : Luck ( ) const
{
si8 ret = luck ;
2009-07-22 12:31:20 +03:00
if ( hasFeatureOfType ( StackFeature : : NO_LUCK ) )
return 0 ;
2009-05-24 20:35:11 +03:00
ret + = valOfFeatures ( StackFeature : : LUCK_BONUS ) ; //fortune & misfortune & other
if ( hasFeatureOfType ( StackFeature : : SELF_LUCK ) ) //eg. halfling
2009-02-06 13:50:48 +02:00
{
2009-05-24 20:35:11 +03:00
ret = std : : max < si8 > ( ret , + 1 ) ;
2009-02-06 13:50:48 +02:00
}
2009-05-24 20:35:11 +03:00
2009-02-06 13:50:48 +02:00
if ( ret > 3 ) ret = 3 ;
if ( ret < - 3 ) ret = - 3 ;
2009-02-05 11:49:45 +02:00
return ret ;
}
2009-03-29 15:02:37 +03:00
2009-05-01 16:42:41 +03:00
si32 CStack : : Attack ( ) const
{
2009-05-17 18:24:50 +03:00
si32 ret = creature - > attack ; //value to be returned
2009-05-01 16:42:41 +03:00
2009-05-17 18:24:50 +03:00
if ( hasFeatureOfType ( StackFeature : : IN_FRENZY ) ) //frenzy for attacker
2009-05-01 16:42:41 +03:00
{
2009-09-04 17:11:42 +03:00
ret + = si32 ( VLC - > spellh - > spells [ 56 ] . powers [ getEffect ( 56 ) - > level ] / 100.0 ) * Defense ( false ) ;
2009-05-01 16:42:41 +03:00
}
2009-06-30 15:28:22 +03:00
ret + = valOfFeatures ( StackFeature : : ATTACK_BONUS ) ;
2009-05-01 16:42:41 +03:00
return ret ;
}
2009-05-17 18:24:50 +03:00
si32 CStack : : Defense ( bool withFrenzy /*= true*/ ) const
2009-05-01 16:42:41 +03:00
{
2009-05-17 18:24:50 +03:00
si32 ret = creature - > defence ;
2009-05-01 16:42:41 +03:00
2009-05-17 18:24:50 +03:00
if ( withFrenzy & & getEffect ( 56 ) ) //frenzy for defender
2009-05-01 16:42:41 +03:00
{
return 0 ;
}
2009-06-30 15:28:22 +03:00
ret + = valOfFeatures ( StackFeature : : DEFENCE_BONUS ) ;
2009-05-01 16:42:41 +03:00
return ret ;
}
2009-06-28 16:49:39 +03:00
ui16 CStack : : MaxHealth ( ) const
{
return creature - > hitPoints + valOfFeatures ( StackFeature : : HP_BONUS ) ;
}
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 ( )
2009-09-20 15:47:40 +03:00
& & ! hasFeatureOfType ( StackFeature : : NOT_ACTIVE , - 1024 , turn ) ; //eg. Ammo Cart
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
}
2009-08-05 03:05:37 +03:00
CGHeroInstance * CGameState : : HeroesPool : : pickHeroFor ( bool native , int player , const CTown * town , std : : map < ui32 , CGHeroInstance * > & available ) 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
{
2009-08-05 03:05:37 +03:00
if ( pavailable . find ( i - > first ) - > second & 1 < < player )
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 ] ) ;
}
2008-08-13 12:28:06 +03:00
CGTownInstance * CGameState : : getTown ( int objid )
{
if ( objid < 0 | | objid > = map - > objects . size ( ) )
return NULL ;
return static_cast < CGTownInstance * > ( map - > objects [ 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 )
{
case 65 : //random artifact
2009-09-28 17:21:48 +03:00
return std : : pair < int , int > ( 5 , ( ran ( ) % 136 ) + 7 ) ; //the only reasonable range - there are siege weapons and blanks we must ommit
2008-06-30 03:06:41 +03:00
case 66 : //random treasure artifact
2009-10-26 11:11:10 +02:00
return std : : pair < int , int > ( 5 , VLC - > arth - > treasures [ ran ( ) % VLC - > arth - > treasures . size ( ) ] - > id ) ;
2008-06-30 03:06:41 +03:00
case 67 : //random minor artifact
2009-10-26 11:11:10 +02:00
return std : : pair < int , int > ( 5 , VLC - > arth - > minors [ ran ( ) % VLC - > arth - > minors . size ( ) ] - > id ) ;
2008-06-30 03:06:41 +03:00
case 68 : //random major artifact
return std : : pair < int , int > ( 5 , VLC - > arth - > majors [ ran ( ) % VLC - > arth - > majors . size ( ) ] - > id ) ;
case 69 : //random relic artifact
return std : : pair < int , int > ( 5 , VLC - > arth - > relics [ ran ( ) % VLC - > arth - > relics . size ( ) ] - > id ) ;
2009-10-26 11:11:10 +02:00
/*case 65: //random artifact //TODO: apply new randndomization system
return std : : pair < int , int > ( 5 , cb . getRandomArt ( CArtifact : : ART_TREASURE | CArtifact : : ART_MINOR | CArtifact : : ART_MAJOR | CArtifact : : ART_RELIC ) ) ;
case 66 : //random treasure artifact
return std : : pair < int , int > ( 5 , cb . getRandomArt ( CArtifact : : ART_TREASURE ) ) ;
case 67 : //random minor artifact
return std : : pair < int , int > ( 5 , cb . getRandomArt ( CArtifact : : ART_MINOR ) ) ;
case 68 : //random major artifact
return std : : pair < int , int > ( 5 , cb . getRandomArt ( CArtifact : : ART_MAJOR ) ) ;
case 69 : //random relic artifact
return std : : pair < int , int > ( 5 , cb . 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
{
int r ;
do
{
r = ran ( ) % 197 ;
} while ( vstd : : contains ( VLC - > creh - > notUsedMonsters , r ) ) ;
return std : : pair < int , int > ( 54 , r ) ;
}
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 ;
2009-05-01 17:37:25 +03:00
CCreGen2ObjInfo * info = static_cast < CCreGen2ObjInfo * > ( obj - > 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 ;
2008-06-30 03:06:41 +03:00
return std : : pair < int , int > ( 17 , 0 ) ;
}
case 217 :
{
int faction = ran ( ) % F_NUMBER ;
2009-05-01 17:37:25 +03:00
CCreGenObjInfo * info = static_cast < CCreGenObjInfo * > ( obj - > 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 ;
2008-06-30 03:06:41 +03:00
return std : : pair < int , int > ( 17 , 0 ) ;
}
case 218 :
{
2009-05-01 17:37:25 +03:00
CCreGen3ObjInfo * info = static_cast < CCreGen3ObjInfo * > ( obj - > 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 ) ;
}
}
return std : : pair < int , int > ( - 1 , - 1 ) ;
}
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 ) ;
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 ] ;
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 ] ;
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 )
{
case 0 :
return day ;
break ;
case 1 :
temp = ( day ) % 7 ;
if ( temp )
return temp ;
else return 7 ;
break ;
case 2 :
temp = ( ( day - 1 ) / 7 ) + 1 ;
if ( ! ( temp % 4 ) )
return 4 ;
else
return ( temp % 4 ) ;
break ;
case 3 :
return ( ( day - 1 ) / 28 ) + 1 ;
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 ;
2008-07-27 20:07:37 +03:00
}
CGameState : : ~ CGameState ( )
{
delete mx ;
2009-01-11 00:08:18 +02:00
delete map ;
delete curB ;
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
}
2008-07-25 20:28:28 +03:00
void CGameState : : init ( StartInfo * si , Mapa * map , int Seed )
2008-06-30 03:06:41 +03:00
{
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 ;
this - > map = map ;
2008-11-28 03:36:34 +02:00
loadTownDInfos ( ) ;
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 ;
}
}
//randomizing objects
2009-05-07 08:01:45 +03:00
for ( unsigned int no = 0 ; no < map - > objects . size ( ) ; + + no )
2008-06-30 03:06:41 +03:00
{
randomizeObject ( map - > objects [ no ] ) ;
if ( map - > objects [ no ] - > ID = = 26 )
2008-09-20 21:30:37 +03:00
{
2008-06-30 03:06:41 +03:00
map - > objects [ no ] - > defInfo - > handler = NULL ;
2008-09-20 21:30:37 +03:00
}
2009-01-06 20:42:20 +02:00
map - > objects [ no ] - > hoverName = VLC - > generaltexth - > names [ map - > objects [ no ] - > ID ] ;
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 ] ;
}
2009-10-04 05:02:45 +03:00
tis . open ( DATA_DIR " /config/resources.txt " ) ;
2008-09-07 06:38:37 +03:00
tis > > k ;
int pom ;
for ( int i = 0 ; i < k ; i + + )
{
tis > > pom ;
resVals . push_back ( pom ) ;
}
2008-06-30 03:06:41 +03:00
/*************************HEROES************************************************/
2008-10-26 22:58:34 +02:00
std : : set < int > hids ;
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 ) ;
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 ) ;
}
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 ) ;
}
BOOST_FOREACH ( int hid , hids ) //all not used allowed heroes go into the pool
{
CGHeroInstance * vhi = new CGHeroInstance ( ) ;
vhi - > initHero ( hid ) ;
hpool . heroesPool [ hid ] = vhi ;
hpool . pavailable [ hid ] = 0xff ;
}
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
}
/*************************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 :
{
2008-08-27 13:19:18 +03:00
if ( ! k - > second . heroes . size ( ) )
2008-08-26 00:14:00 +03:00
{
2008-09-19 15:09:15 +03:00
tlog5 < < " Cannot give starting artifact - no heroes! " < < std : : endl ;
2008-08-26 00:14:00 +03:00
break ;
}
CArtifact * toGive ;
do
{
2008-08-27 13:19:18 +03:00
toGive = VLC - > arth - > treasures [ ran ( ) % VLC - > arth - > treasures . size ( ) ] ;
2008-08-26 00:14:00 +03:00
} while ( ! map - > allowedArtifact [ toGive - > id ] ) ;
CGHeroInstance * hero = k - > second . heroes [ 0 ] ;
std : : vector < ui16 > : : iterator slot = vstd : : findFirstNot ( hero - > artifWorn , toGive - > possibleSlots ) ;
if ( slot ! = toGive - > possibleSlots . end ( ) )
2009-07-11 02:40:10 +03:00
{
2008-08-26 00:14:00 +03:00
hero - > artifWorn [ * slot ] = toGive - > id ;
2009-07-11 02:40:10 +03:00
hero - > recreateArtBonuses ( ) ;
}
2008-08-26 00:14:00 +03:00
else
hero - > artifacts . push_back ( toGive - > id ) ;
}
}
2008-06-30 03:06:41 +03:00
}
/****************************TOWNS************************************************/
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 ) ;
}
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 ;
}
2008-09-01 03:25:36 +03:00
//init garrisons
for ( std : : map < si32 , std : : pair < ui32 , si32 > > : : iterator j = vti - > army . slots . begin ( ) ; j ! = vti - > army . slots . end ( ) ; j + + )
{
if ( j - > second . first > 196 & & j - > second . first < 211 )
{
if ( j - > second . first % 2 )
j - > second . first = vti - > town - > basicCreatures [ ( j - > second . first - 197 ) / 2 ] ;
else
j - > second . first = vti - > town - > upgradedCreatures [ ( j - > second . first - 197 ) / 2 ] ;
}
}
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 ;
2009-10-06 03:32:33 +03:00
if ( curB - > heroes [ 0 ] - > hasBonusOfType ( HeroBonus : : ENEMY_CANT_ESCAPE ) //eg. one of heroes is wearing shakles of war
| | curB - > heroes [ 0 ] - > hasBonusOfType ( HeroBonus : : 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
2009-08-05 15:46:08 +03:00
| | ( curB - > stacks [ g ] - > hasFeatureOfType ( StackFeature : : DOUBLE_WIDE )
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
}
2009-09-25 15:33:29 +03:00
UpgradeInfo CGameState : : getUpgradeInfo ( const CArmedInstance * obj , int stackPos )
2008-08-15 15:11:42 +03:00
{
UpgradeInfo ret ;
2009-10-24 06:28:14 +03:00
const CCreature * base = & VLC - > creh - > creatures [ obj - > army . slots . find ( stackPos ) - > second . first ] ;
2009-02-06 16:15:45 +02:00
if ( ( obj - > ID = = TOWNI_TYPE ) | | ( ( obj - > ID = = HEROI_TYPE ) & & static_cast < const CGHeroInstance * > ( obj ) - > visitedTown ) )
2008-08-15 15:11:42 +03:00
{
2009-09-25 15:33:29 +03:00
const CGTownInstance * t ;
2009-02-06 16:15:45 +02:00
if ( obj - > ID = = TOWNI_TYPE )
2009-09-25 15:33:29 +03:00
t = static_cast < const CGTownInstance * > ( obj ) ;
2008-08-15 15:11:42 +03:00
else
t = static_cast < const CGHeroInstance * > ( obj ) - > visitedTown ;
2009-09-25 15:33:29 +03:00
for ( std : : set < si32 > : : const_iterator i = t - > builtBuildings . begin ( ) ; i ! = t - > builtBuildings . end ( ) ; i + + )
2008-08-15 15:11:42 +03:00
{
if ( ( * i ) > = 37 & & ( * i ) < 44 ) //upgraded creature dwelling
{
int nid = t - > town - > upgradedCreatures [ ( * i ) - 37 ] ; //upgrade offered by that building
if ( base - > upgrades . find ( nid ) ! = base - > upgrades . end ( ) ) //possible upgrade
{
ret . newID . push_back ( nid ) ;
ret . cost . push_back ( std : : set < std : : pair < int , int > > ( ) ) ;
for ( int j = 0 ; j < RESOURCE_QUANTITY ; j + + )
{
int dif = VLC - > creh - > creatures [ nid ] . cost [ j ] - base - > cost [ j ] ;
if ( dif )
ret . cost [ ret . cost . size ( ) - 1 ] . insert ( std : : make_pair ( j , dif ) ) ;
}
}
}
} //end for
}
//TODO: check if hero ability makes some upgrades possible
if ( ret . newID . size ( ) )
ret . oldID = base - > idNumber ;
return ret ;
}
2008-09-07 06:38:37 +03:00
float CGameState : : getMarketEfficiency ( int player , int mode /*=0*/ )
{
boost : : shared_lock < boost : : shared_mutex > lock ( * mx ) ;
if ( mode ) return - 1 ; //todo - support other modes
int mcount = 0 ;
2009-05-07 08:01:45 +03:00
for ( unsigned int i = 0 ; i < getPlayer ( player ) - > towns . size ( ) ; i + + )
2009-03-09 12:37:49 +02:00
if ( vstd : : contains ( getPlayer ( player ) - > towns [ i ] - > builtBuildings , 14 ) )
2008-09-07 06:38:37 +03:00
mcount + + ;
float ret = std : : min ( ( ( float ) mcount + 1.0f ) / 20.0f , 0.5f ) ;
return ret ;
}
2008-09-23 13:58:54 +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
2009-08-30 15:47:40 +03:00
void CGameState : : getNeighbours ( const TerrainTile & srct , int3 tile , std : : vector < int3 > & vec , const boost : : logic : : tribool & onLand )
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 ) ;
if ( ( indeterminate ( onLand ) | | onLand = = ( hlpt . tertype ! = 8 ) )
& & hlpt . tertype ! = 9 )
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 ) ;
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 ;
2009-08-30 15:47:40 +03:00
getNeighbours ( d , dest , vec , s . tertype ! = TerrainTile : : water ) ;
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-02-20 17:44:49 +02:00
int CGameState : : canBuildStructure ( const CGTownInstance * t , int ID )
{
int ret = 7 ; //allowed by default
//checking resources
CBuilding * pom = VLC - > buildh - > buildings [ t - > subID ] [ ID ] ;
2009-08-05 12:46:55 +03:00
2009-08-04 04:00:47 +03:00
if ( ! pom ) return 8 ;
2009-08-05 12:46:55 +03:00
if ( pom - > Name ( ) . size ( ) = = 0 | | pom - > resources . size ( ) = = 0 ) return 2 ; //TODO: why does this happen?
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
}
//checking for requirements
for ( std : : set < int > : : iterator ri = VLC - > townh - > requirements [ t - > subID ] [ ID ] . begin ( ) ;
ri ! = VLC - > townh - > requirements [ t - > subID ] [ ID ] . end ( ) ;
ri + + )
{
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
else if ( t - > builded > = MAX_BUILDING_PER_TURN )
ret = 5 ; //building limit
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
}
2009-03-09 12:37:49 +02:00
PlayerState * CGameState : : getPlayer ( ui8 color )
{
if ( vstd : : contains ( players , color ) )
{
return & players [ color ] ;
}
else
{
tlog2 < < " Warning: Cannot find info for player " < < int ( color ) < < std : : endl ;
return NULL ;
}
}
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 ) ;
tribool blockLandSea ; //true - blocks sea, false - blocks land, indeterminate - allows all
if ( ! hero - > canWalkOnSea ( ) )
2009-05-07 20:20:41 +03:00
blockLandSea = ( map - > getTile ( hpos ) . tertype ! = TerrainTile : : water ) ; //block land if hero is on water and vice versa
2009-03-19 16:17:19 +02:00
else
blockLandSea = boost : : logic : : indeterminate ;
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 ;
2009-05-07 20:20:41 +03:00
if ( ( tinfo - > tertype = = TerrainTile : : rock ) //it's rock
| | ( ( blockLandSea ) & & ( tinfo - > tertype = = TerrainTile : : water ) ) //it's sea and we cannot walk on sea
| | ( ( ! blockLandSea ) & & ( tinfo - > tertype ! = TerrainTile : : water ) ) //it's land and we cannot walk on land
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
}
if ( blockLandSea & & t - > tertype = = TerrainTile : : water ) //hero can walk only on land and dst lays on the water
{
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
}
else if ( ! blockLandSea & & t - > tertype ! = TerrainTile : : water ) //hero is moving by water
{
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
2009-08-30 15:47:40 +03:00
getNeighbours ( map - > getTile ( cp . coord ) , cp . coord , neighbours , boost : : logic : : indeterminate ) ;
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-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 ;
//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 ] ;
node . accessible = ( tinfo - > blocked ? CGPathNode : : BLOCKED : CGPathNode : : ACCESSIBLE ) ;
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
if ( tinfo - > tertype = = TerrainTile : : rock //it's rock
| | onLand & & ! node . land //it's sea and we cannot walk on sea
| | ! onLand & & node . land //it's land and we cannot walk on land
| | ! FoW [ i ] [ j ] [ k ] //tile is covered by the FoW
)
{
node . accessible = CGPathNode : : BLOCKED ;
}
else if ( tinfo - > visitable )
{
for ( size_t ii = 0 ; ii < tinfo - > visitableObjects . size ( ) ; ii + + )
{
2009-11-24 22:29:50 +02:00
const CGObjectInstance * const obj = tinfo - > visitableObjects [ ii ] ;
if ( obj - > blockVisit )
2009-08-30 15:47:40 +03:00
{
node . accessible = CGPathNode : : BLOCKVIS ;
break ;
}
2009-11-24 22:29:50 +02:00
else if ( obj - > ID ! = 26 ) //pathfinder should ignore placed events
{
2009-08-30 15:47:40 +03:00
node . accessible = CGPathNode : : VISITABLE ;
2009-11-24 22:29:50 +02:00
}
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 ] ) ;
ui32 curDist = 0xffffffff ; //total cost of path - init with max possible val
std : : vector < int3 > neighbours ;
neighbours . reserve ( 8 ) ;
while ( ! mq . empty ( ) )
{
CGPathNode * cp = mq . front ( ) ;
mq . pop ( ) ;
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
getNeighbours ( ct , cp - > coord , neighbours , boost : : logic : : indeterminate ) ;
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
}
2009-08-30 15:47:40 +03:00
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
2009-08-30 15:47:40 +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 ;
if ( dp . accessible = = CGPathNode : : ACCESSIBLE )
{
mq . push ( & dp ) ;
}
}
} //neighbours loop
} //queue loop
}
2009-08-28 12:03:58 +03:00
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 ;
}
2009-08-29 20:09:07 +03:00
std : : pair < ui32 , ui32 > BattleInfo : : calculateDmgRange ( const CStack * attacker , const CStack * defender , const CGHeroInstance * attackerHero , const CGHeroInstance * defendingHero , bool shooting , ui8 charge )
2008-08-02 18:08:03 +03:00
{
2009-09-04 17:11:42 +03:00
float attackDefenseBonus ,
2009-03-28 02:38:48 +02:00
minDmg = attacker - > creature - > damageMin * attacker - > amount ,
maxDmg = attacker - > creature - > damageMax * attacker - > amount ;
2009-09-04 17:11:42 +03:00
if ( attacker - > creature - > idNumber = = 149 ) //arrow turret
{
switch ( attacker - > position )
{
case - 2 : //keep
minDmg = 15 ;
maxDmg = 15 ;
break ;
case - 3 : case - 4 : //turrets
minDmg = 7.5f ;
maxDmg = 7.5f ;
break ;
}
}
2009-09-05 17:10:26 +03:00
if ( attacker - > hasFeatureOfType ( StackFeature : : SIEGE_WEAPON ) & & attacker - > creature - > 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 ;
}
2009-08-07 14:22:17 +03:00
if ( attacker - > hasFeatureOfType ( StackFeature : : GENERAL_ATTACK_REDUCTION ) )
{
attackDefenseBonus = attacker - > Attack ( ) * ( attacker - > valOfFeatures ( StackFeature : : GENERAL_ATTACK_REDUCTION , - 1024 ) / 100.0f ) - defender - > Defense ( ) ;
}
else
{
attackDefenseBonus = attacker - > Attack ( ) - defender - > Defense ( ) ;
}
2009-03-28 02:38:48 +02:00
//calculating total attack/defense skills modifier
2009-05-01 16:42:41 +03:00
2009-05-24 20:35:11 +03:00
if ( ! shooting & & attacker - > hasFeatureOfType ( StackFeature : : ATTACK_BONUS , 0 ) ) //bloodlust handling (etc.)
2008-12-06 18:45:54 +02:00
{
2009-05-24 20:35:11 +03:00
attackDefenseBonus + = attacker - > valOfFeatures ( StackFeature : : ATTACK_BONUS , 0 ) ;
2008-12-06 18:45:54 +02:00
}
2009-05-01 16:42:41 +03:00
2009-05-24 20:35:11 +03:00
if ( shooting & & attacker - > hasFeatureOfType ( StackFeature : : ATTACK_BONUS , 1 ) ) //precision handling (etc.)
2008-12-06 18:45:54 +02:00
{
2009-05-24 20:35:11 +03:00
attackDefenseBonus + = attacker - > valOfFeatures ( StackFeature : : ATTACK_BONUS , 1 ) ;
2008-12-06 18:45:54 +02:00
}
2009-05-01 16:42:41 +03:00
2009-08-07 14:22:17 +03:00
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 ;
switch ( attacker - > getEffect ( 55 ) - > level )
{
case 3 : //expert
{
affectedIds . push_back ( 40 ) ; //giant
affectedIds . push_back ( 41 ) ; //titan
affectedIds . push_back ( 152 ) ; //lord of thunder
} //continue adding ...
case 2 : //advanced
{
affectedIds . push_back ( 12 ) ; //angel
affectedIds . push_back ( 13 ) ; //archangel
affectedIds . push_back ( 54 ) ; //devil
affectedIds . push_back ( 55 ) ; //arch devil
affectedIds . push_back ( 150 ) ; //supreme archangel
affectedIds . push_back ( 153 ) ; //antichrist
} //continue adding ...
case 0 : case 1 : //none and basic
{
affectedIds . push_back ( 26 ) ; //green dragon
affectedIds . push_back ( 27 ) ; //gold dragon
affectedIds . push_back ( 82 ) ; //red dragon
affectedIds . push_back ( 83 ) ; //black dragon
affectedIds . push_back ( 96 ) ; //behemot
affectedIds . push_back ( 97 ) ; //ancient behemot
affectedIds . push_back ( 110 ) ; //hydra
affectedIds . push_back ( 111 ) ; //chaos hydra
affectedIds . push_back ( 132 ) ; //azure dragon
affectedIds . push_back ( 133 ) ; //crystal dragon
affectedIds . push_back ( 134 ) ; //faerie dragon
affectedIds . push_back ( 135 ) ; //rust dragon
affectedIds . push_back ( 151 ) ; //diamond dragon
affectedIds . push_back ( 154 ) ; //blood dragon
affectedIds . push_back ( 155 ) ; //darkness dragon
2009-09-07 05:29:44 +03:00
affectedIds . push_back ( 156 ) ; //ghost behemoth
2009-05-01 16:42:41 +03:00
affectedIds . push_back ( 157 ) ; //hell hydra
break ;
}
}
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
{
if ( defender - > creature - > idNumber = = affectedIds [ g ] )
{
attackDefenseBonus + = VLC - > spellh - > spells [ 55 ] . powers [ attacker - > getEffect ( 55 ) - > level ] ;
break ;
}
}
2008-12-06 18:45:54 +02:00
}
2008-08-02 18:08:03 +03:00
2008-09-29 14:03:30 +03:00
float dmgBonusMultiplier = 1.0f ;
2009-03-28 02:38:48 +02:00
2009-08-22 18:29:30 +03:00
//applying jousting bonus
if ( attacker - > hasFeatureOfType ( StackFeature : : JOUSTING ) & & ! defender - > hasFeatureOfType ( StackFeature : : CHARGE_IMMUNITY ) )
dmgBonusMultiplier + = charge * 0.05f ;
2009-03-28 02:38:48 +02:00
//bonus from attack/defense skills
2008-08-02 18:08:03 +03:00
if ( attackDefenseBonus < 0 ) //decreasing dmg
{
if ( 0.02f * ( - attackDefenseBonus ) > 0.3f )
{
dmgBonusMultiplier + = - 0.3f ;
}
else
{
dmgBonusMultiplier + = 0.02f * attackDefenseBonus ;
}
}
else //increasing dmg
{
if ( 0.05f * attackDefenseBonus > 4.0f )
{
dmgBonusMultiplier + = 4.0f ;
}
else
{
dmgBonusMultiplier + = 0.05f * attackDefenseBonus ;
}
}
2009-03-28 02:38:48 +02:00
* 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 )
{
switch ( attackerHero - > getSecSkillLevel ( 1 ) ) //archery
{
case 1 : //basic
2009-08-23 16:41:57 +03:00
dmgBonusMultiplier + = 0.1f ;
2008-09-29 14:03:30 +03:00
break ;
case 2 : //advanced
2009-08-23 16:41:57 +03:00
dmgBonusMultiplier + = 0.25f ;
2008-09-29 14:03:30 +03:00
break ;
case 3 : //expert
2009-08-23 16:41:57 +03:00
dmgBonusMultiplier + = 0.5f ;
2008-09-29 14:03:30 +03:00
break ;
}
* 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
if ( attackerHero - > getSecSkillLevel ( 1 ) > 0 ) //non-none level
{
//apply artifact premy to archery
2009-08-23 16:41:57 +03:00
dmgBonusMultiplier + = attackerHero - > valOfBonuses ( HeroBonus : : SECONDARY_SKILL_PREMY , 1 ) / 100.0f ;
* 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
}
2008-09-29 14:03:30 +03:00
}
else
{
2009-03-28 02:38:48 +02:00
switch ( attackerHero - > getSecSkillLevel ( 22 ) ) //offense
2008-09-29 14:03:30 +03:00
{
case 1 : //basic
2009-08-23 16:41:57 +03:00
dmgBonusMultiplier + = 0.1f ;
2008-09-29 14:03:30 +03:00
break ;
case 2 : //advanced
2009-08-23 16:41:57 +03:00
dmgBonusMultiplier + = 0.2f ;
2008-09-29 14:03:30 +03:00
break ;
case 3 : //expert
2009-08-23 16:41:57 +03:00
dmgBonusMultiplier + = 0.3f ;
2008-09-29 14:03:30 +03:00
break ;
}
}
}
if ( defendingHero )
{
2009-03-28 02:38:48 +02:00
switch ( defendingHero - > getSecSkillLevel ( 23 ) ) //armorer
2008-09-29 14:03:30 +03:00
{
case 1 : //basic
dmgBonusMultiplier * = 0.95f ;
break ;
case 2 : //advanced
dmgBonusMultiplier * = 0.9f ;
break ;
case 3 : //expert
dmgBonusMultiplier * = 0.85f ;
break ;
}
}
2009-08-23 16:41:57 +03:00
//handling hate effect
if ( attacker - > hasFeatureOfType ( StackFeature : : HATE , defender - > creature - > idNumber ) )
dmgBonusMultiplier + = 0.5f ;
2008-12-06 18:45:54 +02:00
//handling spell effects
2009-05-24 20:35:11 +03:00
if ( ! shooting & & defender - > hasFeatureOfType ( StackFeature : : GENERAL_DAMAGE_REDUCTION , 0 ) ) //eg. shield
2008-12-06 18:45:54 +02:00
{
2009-05-24 20:35:11 +03:00
dmgBonusMultiplier * = float ( defender - > valOfFeatures ( StackFeature : : GENERAL_DAMAGE_REDUCTION , 0 ) ) / 100.0f ;
2008-12-06 18:45:54 +02:00
}
2009-05-24 20:35:11 +03:00
else if ( shooting & & defender - > hasFeatureOfType ( StackFeature : : GENERAL_DAMAGE_REDUCTION , 1 ) ) //eg. air shield
2008-12-06 18:45:54 +02:00
{
2009-05-24 20:35:11 +03:00
dmgBonusMultiplier * = float ( defender - > valOfFeatures ( StackFeature : : 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
{
2009-05-01 16:42:41 +03:00
dmgBonusMultiplier * = 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
2009-03-28 02:38:48 +02:00
minDmg * = dmgBonusMultiplier ;
maxDmg * = dmgBonusMultiplier ;
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 ] ;
2009-09-04 17:11:42 +03:00
return 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 ] ;
2009-09-04 17:11:42 +03:00
return std : : make_pair ( int ( maxDmg ) , int ( maxDmg ) ) ;
2009-03-28 02:38:48 +02:00
}
else
{
2009-09-04 17:11:42 +03:00
return std : : make_pair ( int ( minDmg ) , int ( maxDmg ) ) ;
2009-03-28 02:38:48 +02:00
}
tlog1 < < " We are too far in calculateDmg... \n " ;
2009-08-29 20:09:07 +03:00
return std : : make_pair ( 0 , 0 ) ;
}
ui32 BattleInfo : : calculateDmg ( const CStack * attacker , const CStack * defender , const CGHeroInstance * attackerHero , const CGHeroInstance * defendingHero , bool shooting , ui8 charge )
{
std : : pair < ui32 , ui32 > range = calculateDmgRange ( attacker , defender , attackerHero , defendingHero , shooting , charge ) ;
if ( range . first ! = range . second )
return range . first + rand ( ) % ( range . second - range . first + 1 ) ;
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 ] ;
si32 killed = ( st - > alive ( ) ? st - > baseAmount - st - > amount : st - > baseAmount ) ;
amax ( killed , 0 ) ;
2009-10-02 01:12:30 +03:00
if ( killed )
casualties [ ! st - > attackerOwned ] [ st - > creature - > 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 )
{
for ( std : : list < HeroBonus > : : const_iterator i = h1 - > bonuses . begin ( ) ; i ! = h1 - > bonuses . end ( ) ; i + + )
if ( i - > type = = HeroBonus : : BLOCK_SPELLS_ABOVE_LEVEL )
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 )
{
for ( std : : list < HeroBonus > : : const_iterator i = h2 - > bonuses . begin ( ) ; i ! = h2 - > bonuses . end ( ) ; i + + )
if ( i - > type = = HeroBonus : : BLOCK_SPELLS_ABOVE_LEVEL )
amin ( levelLimit , i - > val ) ;
}
return levelLimit ;
}
2009-05-07 18:19:52 +03:00
std : : set < CStack * > BattleInfo : : getAttackedCreatures ( const CSpell * s , const CGHeroInstance * caster , int destinationTile )
{
std : : set < ui16 > attackedHexes = s - > rangeInHexes ( destinationTile , caster - > getSpellSchoolLevel ( s ) ) ;
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 )
{
if ( ( s - > id = = 24 & & ! stacks [ it ] - > creature - > isUndead ( ) ) //death ripple
| | ( s - > id = = 25 & & stacks [ it ] - > creature - > 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
{
if ( caster - > getSpellSchoolLevel ( s ) < 3 ) /*not expert */
{
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 */
if ( ( VLC - > spellh - > spells [ s - > id ] . positiveness > = 0 & & stacks [ it ] - > owner = = caster - > tempOwner )
| | ( VLC - > spellh - > spells [ s - > id ] . positiveness < = 0 & & stacks [ it ] - > owner ! = caster - > tempOwner )
)
{
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 ;
}
2009-08-06 17:02:21 +03:00
int BattleInfo : : calculateSpellDuration ( const CSpell * spell , const CGHeroInstance * caster )
{
switch ( spell - > id )
{
case 56 : //frenzy
return 1 ;
default : //other spells
return caster - > getPrimSkillLevel ( 2 ) + caster - > valOfBonuses ( HeroBonus : : SPELL_DURATION ) ;
}
}
2009-09-02 17:10:19 +03:00
CStack * BattleInfo : : generateNewStack ( const CGHeroInstance * owner , int creatureID , int amount , int stackID , bool attackerOwned , int slot , int /*TerrainTile::EterrainType*/ terrain , int position ) const
2009-08-06 17:02:21 +03:00
{
2009-08-28 13:05:45 +03:00
CStack * ret = new CStack ( & VLC - > creh - > creatures [ creatureID ] , amount , attackerOwned ? side1 : side2 , stackID , attackerOwned , slot ) ;
2009-08-06 17:02:21 +03:00
if ( owner )
{
ret - > features . push_back ( makeFeature ( StackFeature : : SPEED_BONUS , StackFeature : : WHOLE_BATTLE , 0 , owner - > valOfBonuses ( HeroBonus : : STACKS_SPEED ) , StackFeature : : BONUS_FROM_HERO ) ) ;
//base luck/morale calculations
ret - > morale = owner - > getCurrentMorale ( slot , false ) ;
ret - > luck = owner - > getCurrentLuck ( slot , false ) ;
//other bonuses
ret - > features . push_back ( makeFeature ( StackFeature : : ATTACK_BONUS , StackFeature : : WHOLE_BATTLE , 0 , owner - > getPrimSkillLevel ( 0 ) , StackFeature : : BONUS_FROM_HERO ) ) ;
ret - > features . push_back ( makeFeature ( StackFeature : : DEFENCE_BONUS , StackFeature : : WHOLE_BATTLE , 0 , owner - > getPrimSkillLevel ( 1 ) , StackFeature : : BONUS_FROM_HERO ) ) ;
2009-08-22 15:50:23 +03:00
2009-08-23 23:33:05 +03:00
if ( owner - > hasBonusOfType ( HeroBonus : : STACK_HEALTH_PERCENT ) ) // e.g. Elixir of Life
2009-08-22 15:50:23 +03:00
ret - > features . push_back ( makeFeature ( StackFeature : : HP_BONUS , StackFeature : : WHOLE_BATTLE , 0 ,
2009-08-23 23:33:05 +03:00
( ret - > creature - > hitPoints * owner - > valOfBonuses ( HeroBonus : : STACK_HEALTH_PERCENT ) ) / 100 ,
StackFeature : : BONUS_FROM_HERO ) ) ;
if ( owner - > hasBonusOfType ( HeroBonus : : HP_REGENERATION ) ) // e.g. Elixir of Life
ret - > features . push_back ( makeFeature ( StackFeature : : HP_REGENERATION , StackFeature : : WHOLE_BATTLE , 0 ,
owner - > valOfBonuses ( HeroBonus : : HP_REGENERATION ) , StackFeature : : BONUS_FROM_HERO ) ) ;
if ( owner - > hasBonusOfType ( HeroBonus : : LEVEL_SPELL_IMMUNITY ) ) // e.g. Power of the Dragon Father
ret - > features . push_back ( makeFeature ( StackFeature : : LEVEL_SPELL_IMMUNITY , StackFeature : : WHOLE_BATTLE , 0 ,
owner - > valOfBonuses ( HeroBonus : : LEVEL_SPELL_IMMUNITY ) , StackFeature : : BONUS_FROM_HERO ) ) ;
2009-08-22 15:50:23 +03:00
2009-08-06 17:02:21 +03:00
ret - > features . push_back ( makeFeature ( StackFeature : : HP_BONUS , StackFeature : : WHOLE_BATTLE , 0 , owner - > valOfBonuses ( HeroBonus : : STACK_HEALTH ) , StackFeature : : BONUS_FROM_HERO ) ) ;
ret - > firstHPleft = ret - > MaxHealth ( ) ;
}
else
{
ret - > morale = 0 ;
ret - > luck = 0 ;
}
//native terrain bonuses
int faction = ret - > creature - > faction ;
if ( faction > = 0 & & VLC - > heroh - > nativeTerrains [ faction ] = = terrain )
{
ret - > features . push_back ( makeFeature ( StackFeature : : SPEED_BONUS , StackFeature : : WHOLE_BATTLE , 0 , 1 , StackFeature : : OTHER_SOURCE ) ) ;
ret - > features . push_back ( makeFeature ( StackFeature : : ATTACK_BONUS , StackFeature : : WHOLE_BATTLE , 0 , 1 , StackFeature : : OTHER_SOURCE ) ) ;
ret - > features . push_back ( makeFeature ( StackFeature : : DEFENCE_BONUS , StackFeature : : WHOLE_BATTLE , 0 , 1 , StackFeature : : OTHER_SOURCE ) ) ;
}
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
{
ui32 ret = VLC - > spellh - > spells [ sp - > id ] . costs [ caster - > getSpellSchoolLevel ( sp ) ] ;
//checking for friendly stacks reducing cost of the spell
si32 manaReduction = 0 ;
for ( int g = 0 ; g < stacks . size ( ) ; + + g )
{
if ( stacks [ g ] - > owner = = caster - > tempOwner & & stacks [ g ] - > hasFeatureOfType ( StackFeature : : CHANGES_SPELL_COST_FOR_ALLY ) )
{
amin ( manaReduction , stacks [ g ] - > valOfFeatures ( StackFeature : : CHANGES_SPELL_COST_FOR_ALLY ) ) ;
}
}
return ret + manaReduction ;
}
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!
}
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 ;
getAccessibilityMap ( ac , closest - > hasFeatureOfType ( StackFeature : : DOUBLE_WIDE ) , closest - > attackerOwned , false , occupyable , closest - > hasFeatureOfType ( StackFeature : : FLYING ) , closest - > ID ) ;
int predecessor [ BFIELD_SIZE ] , dist [ BFIELD_SIZE ] ;
2009-09-06 20:46:20 +03:00
makeBFS ( closest - > position , ac , predecessor , dist , closest - > hasFeatureOfType ( StackFeature : : DOUBLE_WIDE ) , closest - > attackerOwned , closest - > hasFeatureOfType ( StackFeature : : 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 ) ;
}
2009-11-08 16:44:58 +02:00
ui32 BattleInfo : : calculateSpellDmg ( const CSpell * sp , const CGHeroInstance * caster , const CStack * affectedCreature ) const
{
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,
//24 - death ripple, 25 - destroy undead, 26 - armageddon
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 ) ;
//check if spell really does damage - if not, return 0
if ( dmgMultipliers . find ( sp - > id ) = = dmgMultipliers . end ( ) )
return 0 ;
ret = caster - > getPrimSkillLevel ( 2 ) * dmgMultipliers [ sp - > id ] + sp - > powers [ caster - > getSpellSchoolLevel ( sp ) ] ;
//applying sorcerery secondary skill
switch ( caster - > getSecSkillLevel ( 25 ) )
{
case 1 : //basic
ret * = 1.05f ;
break ;
case 2 : //advanced
ret * = 1.1f ;
break ;
case 3 : //expert
ret * = 1.15f ;
break ;
}
//applying hero bonuses
if ( sp - > air & & caster - > valOfBonuses ( HeroBonus : : AIR_SPELL_DMG_PREMY ) ! = 0 )
{
ret * = ( 100.0f + caster - > valOfBonuses ( HeroBonus : : AIR_SPELL_DMG_PREMY ) / 100.0f ) ;
}
else if ( sp - > fire & & caster - > valOfBonuses ( HeroBonus : : FIRE_SPELL_DMG_PREMY ) ! = 0 )
{
ret * = ( 100.0f + caster - > valOfBonuses ( HeroBonus : : FIRE_SPELL_DMG_PREMY ) / 100.0f ) ;
}
else if ( sp - > water & & caster - > valOfBonuses ( HeroBonus : : WATER_SPELL_DMG_PREMY ) ! = 0 )
{
ret * = ( 100.0f + caster - > valOfBonuses ( HeroBonus : : WATER_SPELL_DMG_PREMY ) / 100.0f ) ;
}
else if ( sp - > earth & & caster - > valOfBonuses ( HeroBonus : : EARTH_SPELL_DMG_PREMY ) ! = 0 )
{
ret * = ( 100.0f + caster - > valOfBonuses ( HeroBonus : : EARTH_SPELL_DMG_PREMY ) / 100.0f ) ;
}
//affected creature-specific part
if ( affectedCreature )
{
//applying protections - when spell has more then one elements, only one protection should be applied (I think)
if ( sp - > air & & affectedCreature - > hasFeatureOfType ( StackFeature : : SPELL_DAMAGE_REDUCTION , 0 ) ) //air spell & protection from air
{
ret * = affectedCreature - > valOfFeatures ( StackFeature : : SPELL_DAMAGE_REDUCTION , 0 ) ;
ret / = 100 ;
}
else if ( sp - > fire & & affectedCreature - > hasFeatureOfType ( StackFeature : : SPELL_DAMAGE_REDUCTION , 1 ) ) //fire spell & protection from fire
{
ret * = affectedCreature - > valOfFeatures ( StackFeature : : SPELL_DAMAGE_REDUCTION , 1 ) ;
ret / = 100 ;
}
else if ( sp - > water & & affectedCreature - > hasFeatureOfType ( StackFeature : : SPELL_DAMAGE_REDUCTION , 2 ) ) //water spell & protection from water
{
ret * = affectedCreature - > valOfFeatures ( StackFeature : : SPELL_DAMAGE_REDUCTION , 2 ) ;
ret / = 100 ;
}
else if ( sp - > earth & & affectedCreature - > hasFeatureOfType ( StackFeature : : SPELL_DAMAGE_REDUCTION , 3 ) ) //earth spell & protection from earth
{
ret * = affectedCreature - > valOfFeatures ( StackFeature : : SPELL_DAMAGE_REDUCTION , 3 ) ;
ret / = 100 ;
}
//general spell dmg reduction
if ( sp - > air & & affectedCreature - > hasFeatureOfType ( StackFeature : : SPELL_DAMAGE_REDUCTION , - 1 ) ) //air spell & protection from air
{
ret * = affectedCreature - > valOfFeatures ( StackFeature : : SPELL_DAMAGE_REDUCTION , - 1 ) ;
ret / = 100 ;
}
//dmg increasing
if ( affectedCreature - > hasFeatureOfType ( StackFeature : : MORE_DAMAGE_FROM_SPELL , sp - > id ) )
{
ret * = 100 + affectedCreature - > valOfFeatures ( StackFeature : : MORE_DAMAGE_FROM_SPELL , sp - > id ) ;
ret / = 100 ;
}
}
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
if ( our - > hasFeatureOfType ( StackFeature : : FORGETFULL ) ) //forgetfulness
return false ;
if ( our - > hasFeatureOfType ( StackFeature : : SHOOTER ) //it's shooter
& & our - > owner ! = dst - > owner
& & dst - > alive ( )
2009-10-06 03:32:33 +03:00
& & ( ! curB - > isStackBlocked ( ID )
| | ourHero - > hasBonusOfType ( HeroBonus : : FREE_SHOOTING ) )
2009-09-04 17:11:42 +03:00
& & our - > shots
)
return true ;
return false ;
}
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
}
2009-09-20 15:47:40 +03:00
else if ( s - > creature - > idNumber = = 145 | | s - > creature - > idNumber = = 149 ) //catapult and turrets are first
{
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
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 ] ;
if ( ! curnode - > theNodeBefore )
return false ;
2009-09-07 05:29:44 +03:00
while ( curnode )
2009-08-30 15:47:40 +03:00
{
out . nodes . push_back ( * curnode ) ;
curnode = curnode - > theNodeBefore ;
}
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
return a - > creature - > idNumber < b - > creature - > idNumber ; //catapult is 145 and turrets are 149
//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 ( )
: color ( - 1 ) , currentSelection ( 0xffffffff )
{
2009-10-04 05:02:45 +03:00
}