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>
# include "hch/CDefObjInfoHandler.h"
# include "hch/CArtHandler.h"
2009-02-20 17:44:49 +02:00
# include "hch/CBuildingHandler.h"
2008-12-27 03:01:59 +02:00
# include "hch/CGeneralTextHandler.h"
2008-06-30 03:06:41 +03:00
# include "hch/CTownHandler.h"
2008-08-20 09:57:53 +03:00
# include "hch/CSpellHandler.h"
2008-06-30 03:06:41 +03:00
# include "hch/CHeroHandler.h"
# include "hch/CObjectHandler.h"
# include "hch/CCreatureHandler.h"
# include "lib/VCMI_Lib.h"
2009-03-07 00:25:19 +02:00
# include "lib/Connection.h"
2008-06-30 03:06:41 +03:00
# include "map.h"
# include "StartInfo.h"
2008-07-26 16:57:32 +03:00
# include "lib/NetPacks.h"
# include <boost/foreach.hpp>
2008-07-27 20:07:37 +03:00
# include <boost/thread.hpp>
# include <boost/thread/shared_mutex.hpp>
2009-03-07 00:25:19 +02:00
2009-03-15 14:53:58 +02:00
# include "lib/RegisterTypes.cpp"
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
2008-12-27 03:01:59 +02:00
std : : string DLL_EXPORT toString ( MetaString & ms )
{
std : : string ret ;
for ( size_t i = 0 ; i < ms . message . size ( ) ; + + i )
{
if ( ms . message [ i ] > 0 )
{
ret + = ms . strings [ ms . message [ i ] - 1 ] ;
}
else
{
std : : vector < std : : string > * vec ;
int type = ms . texts [ - ms . message [ i ] - 1 ] . first ,
ser = ms . texts [ - ms . message [ i ] - 1 ] . second ;
if ( type = = 5 )
{
ret + = VLC - > arth - > artifacts [ ser ] . Name ( ) ;
continue ;
}
else if ( type = = 7 )
{
ret + = VLC - > creh - > creatures [ ser ] . namePl ;
continue ;
}
else if ( type = = 9 )
{
2009-01-06 20:42:20 +02:00
ret + = VLC - > generaltexth - > mines [ ser ] . first ;
2008-12-27 03:01:59 +02:00
continue ;
}
else if ( type = = 10 )
{
2009-01-06 20:42:20 +02:00
ret + = VLC - > generaltexth - > mines [ ser ] . second ;
2008-12-27 03:01:59 +02:00
continue ;
}
2009-03-14 13:25:25 +02:00
else if ( type = = MetaString : : SPELL_NAME )
{
ret + = VLC - > spellh - > spells [ ser ] . name ;
continue ;
}
2008-12-27 03:01:59 +02:00
else
{
switch ( type )
{
case 1 :
vec = & VLC - > generaltexth - > allTexts ;
break ;
case 2 :
2009-01-06 20:42:20 +02:00
vec = & VLC - > generaltexth - > xtrainfo ;
2008-12-27 03:01:59 +02:00
break ;
case 3 :
2009-01-06 20:42:20 +02:00
vec = & VLC - > generaltexth - > names ;
2008-12-27 03:01:59 +02:00
break ;
case 4 :
2009-01-06 20:42:20 +02:00
vec = & VLC - > generaltexth - > restypes ;
2008-12-27 03:01:59 +02:00
break ;
case 6 :
vec = & VLC - > generaltexth - > arraytxt ;
break ;
case 8 :
2009-01-06 20:42:20 +02:00
vec = & VLC - > generaltexth - > creGens ;
2008-12-27 03:01:59 +02:00
break ;
case 11 :
2009-01-06 20:42:20 +02:00
vec = & VLC - > generaltexth - > advobtxt ;
2008-12-27 03:01:59 +02:00
break ;
case 12 :
vec = & VLC - > generaltexth - > artifEvents ;
break ;
}
ret + = ( * vec ) [ ser ] ;
}
}
}
for ( size_t i = 0 ; i < ms . replacements . size ( ) ; + + i )
{
ret . replace ( ret . find ( " %s " ) , 2 , ms . replacements [ i ] ) ;
}
return ret ;
}
2008-10-26 22:58:34 +02:00
2008-07-27 20:07:37 +03:00
CGObjectInstance * createObject ( int id , int subid , int3 pos , int owner )
{
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 ;
}
2008-08-05 02:04:15 +03:00
CStack * BattleInfo : : getStack ( int stackID )
{
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 ] - > ID = = stackID )
return stacks [ g ] ;
}
return NULL ;
}
CStack * BattleInfo : : getStackT ( int tileID )
{
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
| | ( stacks [ g ] - > creature - > isDoubleWide ( ) & & stacks [ g ] - > attackerOwned & & stacks [ g ] - > position - 1 = = tileID )
| | ( stacks [ g ] - > creature - > isDoubleWide ( ) & & ! stacks [ g ] - > attackerOwned & & stacks [ g ] - > position + 1 = = tileID ) )
{
2008-09-12 11:51:46 +03:00
if ( stacks [ g ] - > alive ( ) )
2008-08-05 02:04:15 +03:00
{
return stacks [ g ] ;
}
}
}
return NULL ;
}
2008-08-06 20:49:47 +03:00
void BattleInfo : : getAccessibilityMap ( bool * accessibility , int stackToOmmit )
2008-08-05 02:04:15 +03:00
{
2008-11-10 21:06:04 +02:00
memset ( accessibility , 1 , BFIELD_SIZE ) ; //initialize array with trues
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
{
2008-09-12 11:51:46 +03:00
if ( ! stacks [ g ] - > alive ( ) | | stacks [ g ] - > ID = = stackToOmmit ) //we don't want to lock position of this stack
2008-08-05 02:04:15 +03:00
continue ;
accessibility [ stacks [ g ] - > position ] = false ;
if ( stacks [ g ] - > creature - > isDoubleWide ( ) ) //if it's a double hex creature
{
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
}
}
2008-08-05 02:04:15 +03:00
}
2009-02-05 16:44:27 +02:00
void BattleInfo : : getAccessibilityMapForTwoHex ( bool * accessibility , bool atackerSide , int stackToOmmit , bool addOccupiable ) //send pointer to at least 187 allocated bytes
2008-08-05 02:04:15 +03:00
{
2008-11-10 21:06:04 +02:00
bool mac [ BFIELD_SIZE ] ;
2008-08-06 20:49:47 +03:00
getAccessibilityMap ( mac , stackToOmmit ) ;
2008-11-10 21:06:04 +02:00
memcpy ( accessibility , mac , BFIELD_SIZE ) ;
2008-08-05 02:04:15 +03:00
}
2008-08-06 02:33:08 +03:00
void BattleInfo : : makeBFS ( int start , bool * accessibility , int * predecessor , int * dists ) //both pointers must point to the at least 187-elements int arrays
{
//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 ;
2008-08-05 02:04:15 +03:00
std : : queue < int > hexq ; //bfs queue
hexq . push ( start ) ;
dists [ hexq . front ( ) ] = 0 ;
int curNext = - 1 ; //for bfs loop only (helper var)
while ( ! hexq . empty ( ) ) //bfs loop
{
int curHex = hexq . front ( ) ;
2008-08-06 20:49:47 +03:00
std : : vector < int > neighbours = neighbouringTiles ( curHex ) ;
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
{
2008-08-06 20:49:47 +03:00
curNext = neighbours [ nr ] ;
if ( ! accessibility [ curNext ] | | ( dists [ curHex ] + 1 ) > = dists [ curNext ] )
continue ;
2008-08-05 02:04:15 +03:00
hexq . push ( curNext ) ;
dists [ curNext ] = dists [ curHex ] + 1 ;
predecessor [ curNext ] = curHex ;
}
}
2008-08-06 02:33:08 +03:00
} ;
2009-02-05 16:44:27 +02:00
std : : vector < int > BattleInfo : : getAccessibility ( int stackID , bool addOccupiable )
2008-08-06 02:33:08 +03:00
{
std : : vector < int > ret ;
2008-11-10 21:06:04 +02:00
bool ac [ BFIELD_SIZE ] ;
2008-08-06 02:33:08 +03:00
CStack * s = getStack ( stackID ) ;
if ( s - > creature - > isDoubleWide ( ) )
2009-02-05 16:44:27 +02:00
getAccessibilityMapForTwoHex ( ac , s - > attackerOwned , stackID , addOccupiable ) ;
2008-08-06 02:33:08 +03:00
else
2008-08-06 20:49:47 +03:00
getAccessibilityMap ( ac , stackID ) ;
2008-08-06 02:33:08 +03:00
2008-11-10 21:06:04 +02:00
int pr [ BFIELD_SIZE ] , dist [ BFIELD_SIZE ] ;
2008-08-06 02:33:08 +03:00
makeBFS ( s - > position , ac , pr , dist ) ;
2009-02-14 15:49:30 +02:00
if ( s - > creature - > isDoubleWide ( ) )
{
if ( ! addOccupiable )
{
std : : vector < int > rem ;
for ( int b = 0 ; b < BFIELD_SIZE ; + + b )
{
if ( ac [ b ] & & ! ( s - > attackerOwned ? ac [ b - 1 ] : ac [ b + 1 ] ) )
{
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 ;
}
else
{
std : : vector < int > rem ;
for ( int b = 0 ; b < BFIELD_SIZE ; + + b )
{
2009-04-04 22:26:41 +03:00
if ( ac [ b ] & & ( ! ac [ b - 1 ] | | dist [ b - 1 ] > s - > Speed ( ) ) & & ( ! ac [ b + 1 ] | | dist [ b + 1 ] > s - > Speed ( ) ) & & b % BFIELD_WIDTH ! = 0 & & b % BFIELD_WIDTH ! = ( BFIELD_WIDTH - 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 ;
}
}
}
2008-08-06 02:33:08 +03:00
2008-11-10 21:06:04 +02:00
for ( int i = 0 ; i < BFIELD_SIZE ; i + + )
2009-04-04 22:26:41 +03:00
if ( dist [ i ] < = s - > Speed ( ) & & ac [ i ] )
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
}
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-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
2008-11-14 20:18:13 +02:00
if ( stacks [ i ] - > creature - > isDoubleWide ( ) )
{
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-03-07 18:05:53 +02:00
std : : pair < std : : vector < int > , int > BattleInfo : : getPath ( int start , int dest , bool * accessibility , bool flyingCreature )
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-03-07 18:05:53 +02:00
if ( flyingCreature )
{
bool acc [ BFIELD_SIZE ] ; //full accessibility table
for ( int b = 0 ; b < BFIELD_SIZE ; + + b ) //initialization of acc
{
acc [ b ] = true ;
}
makeBFS ( start , acc , predecessor , dist ) ;
}
else
{
makeBFS ( start , accessibility , predecessor , dist ) ;
}
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
}
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-01 16:42:41 +03:00
counterAttacks ( 1 ) , shots ( C - > shots ) , state ( ) , effects ( ) , speed ( creature - > speed ) , abilities ( C - > abilities ) , attack ( C - > attack ) , defense ( C - > defence )
2008-06-30 03:06:41 +03:00
{
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-04-04 22:26:41 +03:00
ui32 CStack : : Speed ( ) const
2008-11-09 00:29:19 +02:00
{
int premy = 0 ;
2008-11-10 21:06:04 +02:00
const StackEffect * effect = 0 ;
2008-11-09 00:29:19 +02:00
//haste effect check
effect = getEffect ( 53 ) ;
if ( effect )
premy + = VLC - > spellh - > spells [ effect - > id ] . powers [ effect - > level ] ;
//slow effect check
effect = getEffect ( 54 ) ;
if ( effect )
2009-01-16 19:58:41 +02:00
premy - = ( creature - > speed * VLC - > spellh - > spells [ effect - > id ] . powers [ effect - > level ] ) / 100 ;
2008-11-09 00:29:19 +02:00
//prayer effect check
effect = getEffect ( 48 ) ;
if ( effect )
2008-12-06 18:45:54 +02:00
premy + = VLC - > spellh - > spells [ effect - > id ] . powers [ effect - > level ] ;
2008-11-09 00:29:19 +02:00
//bind effect check
effect = getEffect ( 72 ) ;
if ( effect )
2009-02-14 17:00:29 +02:00
{
premy = creature - > speed ; //don't use '- creature->speed' - speed is unsigned!
premy = - premy ;
}
2009-04-04 22:26:41 +03:00
return speed + premy ;
2008-11-09 00:29:19 +02:00
}
2008-11-10 21:06:04 +02:00
const CStack : : StackEffect * CStack : : getEffect ( ui16 id ) 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 )
return & effects [ i ] ;
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-02-06 13:50:48 +02:00
if ( getEffect ( 49 ) ) //mirth
{
ret + = VLC - > spellh - > spells [ 49 ] . powers [ getEffect ( 49 ) - > level ] ;
}
if ( getEffect ( 50 ) ) //sorrow
{
ret - = VLC - > spellh - > spells [ 50 ] . powers [ getEffect ( 50 ) - > level ] ;
}
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-02-06 13:50:48 +02:00
if ( getEffect ( 51 ) ) //fortune
{
ret + = VLC - > spellh - > spells [ 51 ] . powers [ getEffect ( 51 ) - > level ] ;
}
if ( getEffect ( 52 ) ) //misfortune
{
ret - = VLC - > spellh - > spells [ 52 ] . powers [ getEffect ( 52 ) - > level ] ;
}
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
{
si32 ret = attack ; //value to be returned
if ( getEffect ( 56 ) ) //frenzy for attacker
{
ret + = ( VLC - > spellh - > spells [ 56 ] . powers [ getEffect ( 56 ) - > level ] / 100.0 ) * defense ;
}
if ( getEffect ( 48 ) ) //attacker's prayer handling
{
ret + = VLC - > spellh - > spells [ 48 ] . powers [ getEffect ( 48 ) - > level ] ;
}
if ( getEffect ( 45 ) ) //weakness handling
{
ret - = VLC - > spellh - > spells [ 45 ] . powers [ getEffect ( 45 ) - > level ] ;
}
return ret ;
}
si32 CStack : : Defense ( ) const
{
si32 ret = defense ;
if ( getEffect ( 56 ) ) //frenzy for defender
{
return 0 ;
}
if ( getEffect ( 48 ) ) //defender's prayer handling
{
ret + = VLC - > spellh - > spells [ 48 ] . powers [ getEffect ( 48 ) - > level ] ;
}
if ( getEffect ( 47 ) ) //defender's disrupting ray handling
{
int howMany = howManyEffectsSet ( 47 ) ;
ret - = VLC - > spellh - > spells [ 47 ] . powers [ getEffect ( 47 ) - > level ] * howMany ;
}
if ( getEffect ( 46 ) ) //stone skin handling
{
ret + = VLC - > spellh - > spells [ 46 ] . powers [ getEffect ( 46 ) - > level ] ;
}
return ret ;
}
2009-03-29 15:02:37 +03:00
bool CStack : : willMove ( )
{
return ! vstd : : contains ( state , DEFENDING )
& & ! vstd : : contains ( state , MOVED )
& & alive ( )
& & ! vstd : : contains ( abilities , NOT_ACTIVE ) ; //eg. Ammo Cart
}
2008-11-01 00:41:22 +02:00
CGHeroInstance * CGameState : : HeroesPool : : pickHeroFor ( bool native , int player , const CTown * town , int notThatOne )
{
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 ;
}
std : : vector < CGHeroInstance * > pool ;
int sum = 0 , r ;
if ( native )
{
for ( std : : map < ui32 , CGHeroInstance * > : : iterator i = heroesPool . begin ( ) ; i ! = heroesPool . end ( ) ; i + + )
{
if ( pavailable [ i - > first ] & 1 < < player
& & i - > second - > type - > heroType / 2 = = town - > typeID
& & i - > second - > subID ! = notThatOne
)
{
pool . push_back ( i - > second ) ;
}
}
if ( ! pool . size ( ) )
return pickHeroFor ( false , player , town , notThatOne ) ;
else
return pool [ rand ( ) % pool . size ( ) ] ;
}
else
{
for ( std : : map < ui32 , CGHeroInstance * > : : iterator i = heroesPool . begin ( ) ; i ! = heroesPool . end ( ) ; i + + )
{
if ( pavailable [ i - > first ] & 1 < < player
& & i - > second - > subID ! = notThatOne
)
{
pool . push_back ( i - > second ) ;
sum + = i - > second - > type - > heroClass - > selectionProbability [ town - > typeID ] ;
}
}
if ( ! pool . size ( ) )
{
tlog1 < < " There are no heroes available for player " < < player < < " ! \n " ;
return NULL ;
}
r = rand ( ) % sum ;
2009-05-07 08:01:45 +03: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 ] ;
if ( r < 0 )
return pool [ i ] ;
}
return pool [ pool . size ( ) - 1 ] ;
}
}
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-02-12 16:44:58 +02:00
if ( objid < 0 | | objid > = map - > objects . size ( ) | | map - > objects [ objid ] - > ID ! = 34 )
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 ] ) ;
}
2008-06-30 03:06:41 +03: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
return std : : pair < int , int > ( 5 , ( ran ( ) % 136 ) + 7 ) ; //tylko sensowny zakres - na poczatku sa katapulty itp, na koncu specjalne i blanki
case 66 : //random treasure artifact
return std : : pair < int , int > ( 5 , VLC - > arth - > treasures [ ran ( ) % VLC - > arth - > treasures . size ( ) ] - > id ) ;
case 67 : //random minor artifact
return std : : pair < int , int > ( 5 , VLC - > arth - > minors [ ran ( ) % VLC - > arth - > minors . size ( ) ] - > id ) ;
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 ) ;
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 ) ;
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 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 ;
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 ;
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 ;
int h = pickHero ( i ) ;
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****************************************************/
2008-08-27 13:19:18 +03:00
//TODO: computer player should receive other amount of resource than computer (depending on difficulty)
2008-06-30 03:06:41 +03:00
std : : vector < int > startres ;
std : : ifstream tis ( " config/startres.txt " ) ;
int k ;
for ( int j = 0 ; j < scenarioOps - > difficulty ; j + + )
{
tis > > k ;
for ( int z = 0 ; z < RESOURCE_QUANTITY ; z + + )
tis > > k ;
}
tis > > k ;
for ( int i = 0 ; i < RESOURCE_QUANTITY ; i + + )
{
tis > > k ;
startres . push_back ( k ) ;
}
tis . close ( ) ;
2008-09-07 06:38:37 +03:00
tis . clear ( ) ;
2008-07-25 20:28:28 +03:00
for ( std : : map < ui8 , PlayerState > : : iterator i = players . begin ( ) ; i ! = players . end ( ) ; i + + )
2008-06-30 03:06:41 +03:00
{
( * i ) . second . resources . resize ( RESOURCE_QUANTITY ) ;
for ( int x = 0 ; x < RESOURCE_QUANTITY ; x + + )
( * i ) . second . resources [ x ] = startres [ x ] ;
}
2008-09-07 06:38:37 +03:00
tis . open ( " config/resources.txt " ) ;
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
int3 objCenter = obj - > getSightCenter ( ) ;
int radious = obj - > getSightRadious ( ) ;
for ( int xd = std : : max < int > ( objCenter . x - radious , 0 ) ; xd < = std : : min < int > ( objCenter . x + radious , map - > width - 1 ) ; xd + + )
2008-06-30 03:06:41 +03:00
{
2009-03-12 01:25:59 +02:00
for ( int yd = std : : max < int > ( objCenter . y - radious , 0 ) ; yd < = std : : min < int > ( objCenter . y + radious , map - > height - 1 ) ; yd + + )
2008-06-30 03:06:41 +03:00
{
2009-03-12 01:25:59 +02:00
double distance = objCenter . dist2d ( int3 ( xd , yd , objCenter . z ) ) - 0.5 ;
if ( distance < = radious )
k - > second . fogOfWarMap [ xd ] [ yd ] [ objCenter . z ] = 1 ;
2008-06-30 03:06:41 +03:00
}
}
}
2008-08-26 00:14:00 +03:00
2009-03-12 01:25:59 +02:00
//for(int xd=0; xd<map->width; ++xd) //revealing part of map around heroes
//{
// for(int yd=0; yd<map->height; ++yd)
// {
// for(int ch=0; ch<k->second.heroes.size(); ++ch)
// {
// int deltaX = (k->second.heroes[ch]->getPosition(false).x-xd)*(k->second.heroes[ch]->getPosition(false).x-xd);
// int deltaY = (k->second.heroes[ch]->getPosition(false).y-yd)*(k->second.heroes[ch]->getPosition(false).y-yd);
// if(deltaX+deltaY<k->second.heroes[ch]->getSightDistance()*k->second.heroes[ch]->getSightDistance())
// k->second.fogOfWarMap[xd][yd][k->second.heroes[ch]->getPosition(false).z] = 1;
// }
// }
//}
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 ( ) )
hero - > artifWorn [ * slot ] = toGive - > id ;
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 ;
2009-03-12 01:25:59 +02:00
// for(int xd=0; xd<map->width; ++xd) //revealing part of map around towns
// {
// for(int yd=0; yd<map->height; ++yd)
// {
// for(int ch=0; ch<k->second.towns.size(); ++ch)
// {
// int deltaX = (k->second.towns[ch]->pos.x-xd)*(k->second.towns[ch]->pos.x-xd);
// int deltaY = (k->second.towns[ch]->pos.y-yd)*(k->second.towns[ch]->pos.y-yd);
// if(deltaX+deltaY<k->second.towns[ch]->getSightDistance()*k->second.towns[ch]->getSightDistance())
// k->second.fogOfWarMap[xd][yd][k->second.towns[ch]->pos.z] = 1;
// }
// }
// }
2008-06-30 03:06:41 +03:00
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-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
{
int3 vistile = k - > second . towns [ m ] - > pos ; vistile . x - - ; //tile next to the entrance
2008-08-25 13:25:16 +03:00
if ( vistile = = k - > second . heroes [ l ] - > pos | | k - > second . heroes [ l ] - > pos = = k - > second . towns [ m ] - > pos )
2008-06-30 03:06:41 +03:00
{
k - > second . towns [ m ] - > visitingHero = k - > second . heroes [ l ] ;
2008-08-20 09:57:53 +03:00
k - > second . heroes [ l ] - > visitedTown = k - > second . towns [ m ] ;
k - > second . heroes [ l ] - > inTownGarrison = false ;
2008-08-25 13:25:16 +03:00
if ( k - > second . heroes [ l ] - > pos = = k - > second . towns [ m ] - > pos )
k - > second . heroes [ l ] - > pos . x - = 1 ;
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-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 ( ) ;
}
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 ;
}
int CGameState : : battleGetStack ( int pos )
{
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
| | ( curB - > stacks [ g ] - > creature - > isDoubleWide ( )
& & ( ( curB - > stacks [ g ] - > attackerOwned & & curB - > stacks [ g ] - > position - 1 = = pos )
| | ( ! curB - > stacks [ g ] - > attackerOwned & & curB - > stacks [ g ] - > position + 1 = = pos ) )
) )
& & curB - > stacks [ g ] - > alive ( )
)
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-02-14 15:49:30 +02:00
//std::vector < std::pair<const CGObjectInstance*,SDL_Rect> > & objs = CGI->mh->ttiles[tile.x][tile.y][tile.z].objects;
//for(int g=0; g<objs.size(); ++g)
//{
// switch(objs[g].first->ID)
// {
// case 222: //clover field
// return 19;
// case 223: //cursed ground
// 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;
// case 230: //magic plains
// return 9;
// case 231: //rocklands
// return 15;
// }
//}
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
}
2008-08-15 15:11:42 +03:00
UpgradeInfo CGameState : : getUpgradeInfo ( CArmedInstance * obj , int stackPos )
{
UpgradeInfo ret ;
CCreature * base = & VLC - > creh - > creatures [ obj - > army . slots [ stackPos ] . 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
{
CGTownInstance * t ;
2009-02-06 16:15:45 +02:00
if ( obj - > ID = = TOWNI_TYPE )
2008-08-15 15:11:42 +03:00
t = static_cast < CGTownInstance * > ( const_cast < CArmedInstance * > ( obj ) ) ;
else
t = static_cast < const CGHeroInstance * > ( obj ) - > visitedTown ;
for ( std : : set < si32 > : : iterator i = t - > builtBuildings . begin ( ) ; i ! = t - > builtBuildings . end ( ) ; i + + )
{
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-03-19 16:17:19 +02:00
void CGameState : : getNeighbours ( int3 tile , std : : vector < int3 > & vec , const boost : : logic : : tribool & onLand )
2009-02-12 16:44:58 +02:00
{
vec . clear ( ) ;
int3 hlp ;
bool weAreOnLand = ( map - > getTile ( tile ) . tertype ! = 8 ) ;
if ( tile . x > 0 )
{
hlp = int3 ( tile . x - 1 , tile . y , tile . z ) ;
2009-02-20 12:36:15 +02:00
if ( ( weAreOnLand = = ( map - > getTile ( hlp ) . tertype ! = 8 ) ) & & map - > getTile ( hlp ) . tertype ! = 9 )
2009-02-12 16:44:58 +02:00
vec . push_back ( hlp ) ;
}
if ( tile . y > 0 )
{
hlp = int3 ( tile . x , tile . y - 1 , tile . z ) ;
2009-02-20 12:36:15 +02:00
if ( ( weAreOnLand = = ( map - > getTile ( hlp ) . tertype ! = 8 ) ) & & map - > getTile ( hlp ) . tertype ! = 9 )
2009-02-12 16:44:58 +02:00
vec . push_back ( hlp ) ;
}
if ( tile . x > 0 & & tile . y > 0 )
{
hlp = int3 ( tile . x - 1 , tile . y - 1 , tile . z ) ;
2009-02-20 12:36:15 +02:00
if ( ( weAreOnLand = = ( map - > getTile ( hlp ) . tertype ! = 8 ) ) & & map - > getTile ( hlp ) . tertype ! = 9 )
2009-02-12 16:44:58 +02:00
vec . push_back ( hlp ) ;
}
if ( tile . x > 0 & & tile . y < map - > height - 1 )
{
hlp = int3 ( tile . x - 1 , tile . y + 1 , tile . z ) ;
2009-02-20 12:36:15 +02:00
if ( ( weAreOnLand = = ( map - > getTile ( hlp ) . tertype ! = 8 ) ) & & map - > getTile ( hlp ) . tertype ! = 9 )
2009-02-12 16:44:58 +02:00
vec . push_back ( hlp ) ;
}
if ( tile . y < map - > height - 1 )
{
hlp = int3 ( tile . x , tile . y + 1 , tile . z ) ;
2009-02-20 12:36:15 +02:00
if ( ( weAreOnLand = = ( map - > getTile ( hlp ) . tertype ! = 8 ) ) & & map - > getTile ( hlp ) . tertype ! = 9 )
2009-02-12 16:44:58 +02:00
vec . push_back ( hlp ) ;
}
if ( tile . x < map - > width - 1 )
{
hlp = int3 ( tile . x + 1 , tile . y , tile . z ) ;
2009-02-20 12:36:15 +02:00
if ( ( weAreOnLand = = ( map - > getTile ( hlp ) . tertype ! = 8 ) ) & & map - > getTile ( hlp ) . tertype ! = 9 )
2009-02-12 16:44:58 +02:00
vec . push_back ( hlp ) ;
}
if ( tile . x < map - > width - 1 & & tile . y > 0 )
{
hlp = int3 ( tile . x + 1 , tile . y - 1 , tile . z ) ;
2009-02-20 12:36:15 +02:00
if ( ( weAreOnLand = = ( map - > getTile ( hlp ) . tertype ! = 8 ) ) & & map - > getTile ( hlp ) . tertype ! = 9 )
2009-02-12 16:44:58 +02:00
vec . push_back ( hlp ) ;
}
if ( tile . x < map - > width - 1 & & tile . y < map - > height - 1 )
{
hlp = int3 ( tile . x + 1 , tile . y + 1 , tile . z ) ;
2009-02-20 12:36:15 +02:00
if ( ( weAreOnLand = = ( map - > getTile ( hlp ) . tertype ! = 8 ) ) & & map - > getTile ( hlp ) . tertype ! = 9 )
2009-02-12 16:44:58 +02:00
vec . push_back ( hlp ) ;
}
}
int CGameState : : getMovementCost ( const CGHeroInstance * h , int3 src , int3 dest , int remainingMovePoints , bool checkLast )
{
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-03-19 16:17:19 +02: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 ;
ret * = 1.414 ;
2009-03-19 16:17:19 +02:00
//diagonal move costs too much but normal move is possible - allow diagonal move
2009-02-12 16:44:58 +02:00
if ( ret > remainingMovePoints & & remainingMovePoints > old )
{
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 ;
getNeighbours ( dest , vec , true ) ;
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 ] ;
for ( int res = 0 ; res < 7 ; res + + ) //TODO: support custom amount of resources
{
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-05-07 20:20:41 +03:00
if ( map - > getTile ( t - > pos + int3 ( - 1 , 3 , 0 ) ) . tertype ! = TerrainTile : : water & & map - > getTile ( t - > pos + int3 ( - 3 , 3 , 0 ) ) . tertype ! = TerrainTile : : water )
2009-02-20 17:44:49 +02:00
ret = 1 ; //lack of water
}
return ret ;
}
2009-03-07 00:25:19 +02:00
void CGameState : : apply ( CPack * pack )
{
2009-03-15 17:13:54 +02:00
applierGs - > apps [ typeList . getTypeID ( pack ) ] - > 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-03-19 16:17:19 +02:00
CPath * CGameState : : getPath ( int3 src , int3 dest , const CGHeroInstance * hero )
{
if ( ! map - > isInTheMap ( src ) | | ! map - > isInTheMap ( dest ) ) //check input
return NULL ;
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-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 ] ;
node . accesible = ! tinfo - > blocked ;
if ( i = = dest . x & & j = = dest . y & & tinfo - > visitable )
{
node . accesible = true ; //for allowing visiting objects
}
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-03-19 16:17:19 +02:00
| | ! getPlayer ( hero - > tempOwner ) - > fogOfWarMap [ i ] [ j ] [ src . z ] //tile is covered by the FoW
)
{
node . accesible = false ;
}
}
}
//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
getNeighbours ( cp . coord , neighbours , blockLandSea ) ;
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 ] ;
if ( dp . accesible )
{
int cost = getMovementCost ( hero , cp . coord , dp . coord , hero - > movement - cp . dist ) ;
if ( ( dp . dist = = - 1 | | ( dp . dist > cp . dist + cost ) ) & & dp . accesible & & checkForVisitableDir ( cp . coord , dp . coord ) & & checkForVisitableDir ( dp . coord , cp . coord ) )
{
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
return NULL ;
CPath * ret = new CPath ;
while ( curNode - > coord ! = graph [ src . x ] [ src . y ] . coord )
{
ret - > nodes . push_back ( * curNode ) ;
curNode = curNode - > theNodeBefore ;
}
ret - > nodes . push_back ( graph [ src . x ] [ src . y ] ) ;
return ret ;
}
bool CGameState : : checkForVisitableDir ( const int3 & src , const int3 & dst ) const
{
const TerrainTile * pom = & map - > getTile ( dst ) ;
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 ;
}
2008-09-29 14:03:30 +03:00
int BattleInfo : : calculateDmg ( const CStack * attacker , const CStack * defender , const CGHeroInstance * attackerHero , const CGHeroInstance * defendingHero , bool shooting )
2008-08-02 18:08:03 +03:00
{
2009-05-01 16:42:41 +03:00
int attackDefenseBonus = attacker - > Attack ( ) - defender - > Defense ( ) ,
2009-03-28 02:38:48 +02:00
minDmg = attacker - > creature - > damageMin * attacker - > amount ,
maxDmg = attacker - > creature - > damageMax * attacker - > amount ;
//calculating total attack/defense skills modifier
2009-05-01 16:42:41 +03:00
if ( ! shooting & & attacker - > getEffect ( 43 ) ) //bloodlust handling
2008-12-06 18:45:54 +02:00
{
2009-05-01 16:42:41 +03:00
attackDefenseBonus + = VLC - > spellh - > spells [ 43 ] . powers [ attacker - > getEffect ( 43 ) - > level ] ;
2008-12-06 18:45:54 +02:00
}
2009-05-01 16:42:41 +03:00
if ( shooting & & attacker - > getEffect ( 44 ) ) //precision handling
2008-12-06 18:45:54 +02:00
{
2009-05-01 16:42:41 +03:00
attackDefenseBonus + = VLC - > spellh - > spells [ 44 ] . powers [ attacker - > getEffect ( 44 ) - > level ] ;
2008-12-06 18:45:54 +02: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
affectedIds . push_back ( 156 ) ; //ghost behemot
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
//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
dmgBonusMultiplier * = 1.1f ;
break ;
case 2 : //advanced
dmgBonusMultiplier * = 1.25f ;
break ;
case 3 : //expert
dmgBonusMultiplier * = 1.5f ;
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
dmgBonusMultiplier * = ( 100.0f + attackerHero - > valOfBonuses ( HeroBonus : : SECONDARY_SKILL_PREMY , 1 ) ) / 100.0f ;
}
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
dmgBonusMultiplier * = 1.1f ;
break ;
case 2 : //advanced
dmgBonusMultiplier * = 1.2f ;
break ;
case 3 : //expert
dmgBonusMultiplier * = 1.3f ;
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 ;
}
}
2008-12-06 18:45:54 +02:00
//handling spell effects
if ( ! shooting & & defender - > getEffect ( 27 ) ) //shield
{
2009-05-01 16:42:41 +03:00
dmgBonusMultiplier * = float ( VLC - > spellh - > spells [ 27 ] . powers [ attacker - > getEffect ( 27 ) - > level ] ) / 100.0f ;
2008-12-06 18:45:54 +02:00
}
2009-03-28 02:38:48 +02:00
else if ( shooting & & defender - > getEffect ( 28 ) ) //air shield
2008-12-06 18:45:54 +02:00
{
2009-05-01 16:42:41 +03:00
dmgBonusMultiplier * = float ( VLC - > spellh - > spells [ 28 ] . powers [ attacker - > getEffect ( 28 ) - > level ] ) / 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-03-28 02:38:48 +02:00
return minDmg ;
}
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-03-28 02:38:48 +02:00
return maxDmg ;
}
else
{
if ( minDmg ! = maxDmg )
return minDmg + rand ( ) % ( maxDmg - minDmg + 1 ) ;
else
return minDmg ;
}
tlog1 < < " We are too far in calculateDmg... \n " ;
return - 1 ;
2008-08-17 22:15:31 +03:00
}
2008-09-09 10:05:02 +03:00
void BattleInfo : : calculateCasualties ( std : : set < std : : pair < ui32 , si32 > > * casualties )
{
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
{
2008-09-12 11:51:46 +03:00
if ( ! stacks [ i ] - > alive ( ) )
2008-09-09 10:05:02 +03:00
{
casualties [ ! stacks [ i ] - > attackerOwned ] . insert ( std : : pair < ui32 , si32 > ( stacks [ i ] - > creature - > idNumber , stacks [ i ] - > baseAmount ) ) ;
}
else if ( stacks [ i ] - > amount ! = stacks [ i ] - > baseAmount )
{
casualties [ ! stacks [ i ] - > attackerOwned ] . insert ( std : : pair < ui32 , si32 > ( stacks [ i ] - > creature - > idNumber , stacks [ i ] - > baseAmount - stacks [ i ] - > amount ) ) ;
}
}
2008-11-15 17:26:08 +02:00
}
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 ) ) ;
std : : set < CStack * > attackedCres ; /*std::set to exclude multiple occurences of two hex creatures*/
if ( s - > id = = 24 | | s - > id = = 25 | | s - > id = = 26 ) //death ripple, destroy undead and armageddon
{
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
| | ( s - > id = = 26 ) //armageddon
)
{
attackedCres . insert ( stacks [ it ] ) ;
}
}
}
else if ( 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
{
if ( caster - > getSpellSchoolLevel ( s ) < 3 ) /*not expert */
{
CStack * st = getStackT ( destinationTile ) ;
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 )
)
{
attackedCres . insert ( stacks [ it ] ) ;
}
}
} //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
{
CStack * st = getStackT ( destinationTile ) ;
if ( st )
attackedCres . insert ( st ) ;
}
else //custom range from attackedHexes
{
for ( std : : set < ui16 > : : iterator it = attackedHexes . begin ( ) ; it ! = attackedHexes . end ( ) ; + + it )
{
CStack * st = getStackT ( * it ) ;
if ( st )
attackedCres . insert ( st ) ;
}
}
return attackedCres ;
}
2008-11-15 17:26:08 +02:00
CStack * BattleInfo : : getNextStack ( )
{
CStack * current = getStack ( activeStack ) ;
2009-05-07 08:01:45 +03:00
for ( unsigned int i = 0 ; i < stacks . size ( ) ; i + + ) //find fastest not moved/waited stack (stacks vector is sorted by speed)
2008-11-15 17:26:08 +02:00
{
2009-03-29 15:02:37 +03:00
if ( stacks [ i ] - > willMove ( ) & & ! vstd : : contains ( stacks [ i ] - > state , WAITING ) )
return stacks [ i ] ;
2008-11-15 17:26:08 +02:00
}
for ( int i = stacks . size ( ) - 1 ; i > = 0 ; i - - ) //find slowest waiting stack
{
2009-03-29 15:02:37 +03:00
if ( stacks [ i ] - > willMove ( ) )
return stacks [ i ] ;
2008-11-15 17:26:08 +02:00
}
return NULL ; //all stacks moved or defending!
2008-12-20 19:08:51 +02:00
}
std : : vector < CStack > BattleInfo : : getStackQueue ( )
{
std : : vector < CStack > ret ;
std : : vector < int > taken ; //if non-zero value, corresponding stack has been placed in ret
taken . resize ( stacks . size ( ) ) ;
2009-05-07 08:01:45 +03:00
for ( unsigned int g = 0 ; g < taken . size ( ) ; + + g )
2008-12-20 19:08:51 +02:00
{
taken [ g ] = 0 ;
}
for ( int moved = 0 ; moved < 2 ; + + moved ) //in first cycle we add stacks that can act in current turn, in second one the rest of them
{
2009-05-07 08:01:45 +03:00
for ( unsigned int gc = 0 ; gc < stacks . size ( ) ; + + gc )
2008-12-20 19:08:51 +02:00
{
int id = - 1 , speed = - 1 ;
2009-05-07 08:01:45 +03:00
for ( unsigned int i = 0 ; i < stacks . size ( ) ; + + i ) //find not waited stacks only
2008-12-20 19:08:51 +02:00
{
if ( ( moved = = 1 | | ! vstd : : contains ( stacks [ i ] - > state , DEFENDING ) )
& & stacks [ i ] - > alive ( )
& & ( moved = = 1 | | ! vstd : : contains ( stacks [ i ] - > state , MOVED ) )
& & ! vstd : : contains ( stacks [ i ] - > state , WAITING )
2009-03-29 15:02:37 +03:00
& & taken [ i ] = = 0
& & ! vstd : : contains ( stacks [ i ] - > abilities , NOT_ACTIVE ) ) //eg. Ammo Cart
2008-12-20 19:08:51 +02:00
{
2009-04-04 22:26:41 +03:00
if ( speed = = - 1 | | stacks [ i ] - > Speed ( ) > speed )
2008-12-20 19:08:51 +02:00
{
id = i ;
2009-04-04 22:26:41 +03:00
speed = stacks [ i ] - > Speed ( ) ;
2008-12-20 19:08:51 +02:00
}
}
}
if ( id ! = - 1 )
{
ret . push_back ( * stacks [ id ] ) ;
taken [ id ] = 1 ;
}
else //choose something from not moved stacks
{
int id = - 1 , speed = 10000 ; //infinite speed
2009-05-07 08:01:45 +03:00
for ( unsigned int i = 0 ; i < stacks . size ( ) ; + + i ) //find waited stacks only
2008-12-20 19:08:51 +02:00
{
if ( ( moved = = 1 | | ! vstd : : contains ( stacks [ i ] - > state , DEFENDING ) )
& & stacks [ i ] - > alive ( )
& & ( moved = = 1 | | ! vstd : : contains ( stacks [ i ] - > state , MOVED ) )
& & vstd : : contains ( stacks [ i ] - > state , WAITING )
2009-03-29 15:02:37 +03:00
& & taken [ i ] = = 0
& & ! vstd : : contains ( stacks [ i ] - > abilities , NOT_ACTIVE ) ) //eg. Ammo Cart
2008-12-20 19:08:51 +02:00
{
2009-04-04 22:26:41 +03:00
if ( stacks [ i ] - > Speed ( ) < speed ) //slowest one
2008-12-20 19:08:51 +02:00
{
id = i ;
2009-04-04 22:26:41 +03:00
speed = stacks [ i ] - > Speed ( ) ;
2008-12-20 19:08:51 +02:00
}
}
}
if ( id ! = - 1 )
{
ret . push_back ( * stacks [ id ] ) ;
taken [ id ] = 1 ;
}
else
{
break ; //no stacks have been found, so none of them will be found in next iterations
}
}
}
}
return ret ;
}
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
}