2008-07-25 20:28:28 +03:00
# include "../StartInfo.h"
2008-08-27 13:19:18 +03:00
# include "../hch/CArtHandler.h"
2008-11-28 03:36:34 +02:00
# include "../hch/CBuildingHandler.h"
# include "../hch/CDefObjInfoHandler.h"
2009-01-11 00:08:18 +02:00
# include "../hch/CGeneralTextHandler.h"
2008-11-28 03:36:34 +02:00
# include "../hch/CHeroHandler.h"
2008-07-25 20:28:28 +03:00
# include "../hch/CObjectHandler.h"
2008-09-29 00:24:22 +03:00
# include "../hch/CSpellHandler.h"
2008-07-25 20:28:28 +03:00
# include "../hch/CTownHandler.h"
2009-01-11 00:08:18 +02:00
# include "../CGameState.h"
2008-08-04 18:56:36 +03:00
# include "../lib/CondSh.h"
2008-11-28 03:36:34 +02:00
# include "../lib/Connection.h"
# include "../lib/NetPacks.h"
# include "../lib/VCMI_Lib.h"
# include "../map.h"
# include "CGameHandler.h"
# include <boost/bind.hpp>
# include <boost/date_time/posix_time/posix_time_types.hpp> //no i/o just types
# include <boost/foreach.hpp>
# include <boost/thread.hpp>
# include <boost/thread/shared_mutex.hpp>
2008-09-17 14:55:03 +03:00
# include <fstream>
2008-08-09 02:02:32 +03:00
# ifndef _MSC_VER
2008-08-04 12:05:52 +03:00
# include <boost/thread/xtime.hpp>
2008-08-09 02:02:32 +03:00
# endif
2008-08-04 12:05:52 +03:00
extern bool end2 ;
2008-08-04 18:56:36 +03:00
# include "../lib/BattleAction.h"
# ifdef min
# undef min
# endif
# ifdef max
# undef max
# endif
# define NEW_ROUND BattleNextRound bnr;\
bnr . round = gs - > curB - > round + 1 ; \
sendAndApply ( & bnr ) ;
2008-07-25 20:28:28 +03:00
2008-08-13 03:44:31 +03:00
boost : : mutex gsm ;
ui32 CGameHandler : : QID = 1 ;
2008-08-04 18:56:36 +03:00
CondSh < bool > battleMadeAction ;
CondSh < BattleResult * > battleResult ( NULL ) ;
2008-08-22 15:21:09 +03:00
std : : map < ui32 , CFunctionList < void ( ui32 ) > > callbacks ; //question id => callback function - for selection dialogs
2008-08-13 03:44:31 +03:00
2008-08-04 18:56:36 +03:00
class CMP_stack
{
public :
2008-11-10 21:06:04 +02:00
inline bool operator ( ) ( const CStack * a , const CStack * b )
2008-08-04 18:56:36 +03:00
{
2008-11-10 21:06:04 +02:00
return ( a - > speed ( ) ) > ( b - > speed ( ) ) ;
2008-08-04 18:56:36 +03:00
}
} cmpst ;
2008-07-29 12:53:27 +03:00
double distance ( int3 a , int3 b )
2008-07-28 15:44:08 +03:00
{
return std : : sqrt ( ( double ) ( a . x - b . x ) * ( a . x - b . x ) + ( a . y - b . y ) * ( a . y - b . y ) ) ;
}
2008-11-09 00:29:19 +02:00
int getSchoolLevel ( const CGHeroInstance * h , const CSpell * s )
{
2008-12-31 11:33:46 +02:00
ui8 ret = 0 ;
2008-11-09 00:29:19 +02:00
if ( s - > fire )
ret = std : : max ( ret , h - > getSecSkillLevel ( 14 ) ) ;
if ( s - > air )
ret = std : : max ( ret , h - > getSecSkillLevel ( 15 ) ) ;
if ( s - > water )
ret = std : : max ( ret , h - > getSecSkillLevel ( 16 ) ) ;
if ( s - > earth )
ret = std : : max ( ret , h - > getSecSkillLevel ( 17 ) ) ;
return ret ;
}
2008-09-29 13:16:02 +03:00
void giveExp ( BattleResult & r )
{
r . exp [ 0 ] = 0 ;
r . exp [ 1 ] = 0 ;
for ( std : : set < std : : pair < ui32 , si32 > > : : iterator i = r . casualties [ ! r . winner ] . begin ( ) ; i ! = r . casualties [ ! r . winner ] . end ( ) ; i + + )
{
r . exp [ r . winner ] + = VLC - > creh - > creatures [ i - > first ] . hitPoints * i - > second ;
}
}
2008-07-30 20:51:19 +03:00
//bool CGameState::checkFunc(int obid, std::string name)
//{
// if (objscr.find(obid)!=objscr.end())
// {
// if(objscr[obid].find(name)!=objscr[obid].end())
// {
// return true;
// }
// }
// return false;
//}
2008-08-13 03:44:31 +03:00
PlayerStatus PlayerStatuses : : operator [ ] ( ui8 player )
{
boost : : unique_lock < boost : : mutex > l ( mx ) ;
if ( players . find ( player ) ! = players . end ( ) )
{
return players [ player ] ;
}
else
{
throw std : : string ( " No such player! " ) ;
}
}
void PlayerStatuses : : addPlayer ( ui8 player )
{
boost : : unique_lock < boost : : mutex > l ( mx ) ;
players [ player ] ;
}
bool PlayerStatuses : : hasQueries ( ui8 player )
{
boost : : unique_lock < boost : : mutex > l ( mx ) ;
if ( players . find ( player ) ! = players . end ( ) )
{
return players [ player ] . queries . size ( ) ;
}
else
{
throw std : : string ( " No such player! " ) ;
}
}
bool PlayerStatuses : : checkFlag ( ui8 player , bool PlayerStatus : : * flag )
{
boost : : unique_lock < boost : : mutex > l ( mx ) ;
if ( players . find ( player ) ! = players . end ( ) )
{
return players [ player ] . * flag ;
}
else
{
throw std : : string ( " No such player! " ) ;
}
}
void PlayerStatuses : : setFlag ( ui8 player , bool PlayerStatus : : * flag , bool val )
{
boost : : unique_lock < boost : : mutex > l ( mx ) ;
if ( players . find ( player ) ! = players . end ( ) )
{
players [ player ] . * flag = val ;
}
else
{
throw std : : string ( " No such player! " ) ;
}
cv . notify_all ( ) ;
}
void PlayerStatuses : : addQuery ( ui8 player , ui32 id )
{
boost : : unique_lock < boost : : mutex > l ( mx ) ;
if ( players . find ( player ) ! = players . end ( ) )
{
players [ player ] . queries . insert ( id ) ;
}
else
{
throw std : : string ( " No such player! " ) ;
}
cv . notify_all ( ) ;
}
void PlayerStatuses : : removeQuery ( ui8 player , ui32 id )
{
boost : : unique_lock < boost : : mutex > l ( mx ) ;
if ( players . find ( player ) ! = players . end ( ) )
{
players [ player ] . queries . erase ( id ) ;
}
else
{
throw std : : string ( " No such player! " ) ;
}
cv . notify_all ( ) ;
}
2008-12-22 19:48:41 +02:00
//void CGameHandler::handleCPPObjS(std::map<int,CCPPObjectScript*> * mapa, CCPPObjectScript * script)
//{
// std::vector<int> tempv = script->yourObjects();
// for (unsigned i=0;i<tempv.size();i++)
// {
// (*mapa)[tempv[i]]=script;
// }
// cppscripts.insert(script);
//}
2008-08-13 03:44:31 +03:00
template < typename T >
void callWith ( std : : vector < T > args , boost : : function < void ( T ) > fun , ui32 which )
{
fun ( args [ which ] ) ;
}
2009-01-11 00:08:18 +02:00
void CGameHandler : : changeSecSkill ( int ID , int which , int val , bool abs /*=false*/ )
2008-08-13 03:44:31 +03:00
{
2009-01-11 00:08:18 +02:00
SetSecSkill sss ;
sss . id = ID ;
sss . which = which ;
sss . val = val ;
sss . abs = abs ;
sendAndApply ( & sss ) ;
2008-08-13 03:44:31 +03:00
}
2009-01-11 00:08:18 +02:00
2008-08-04 18:56:36 +03:00
void CGameHandler : : changePrimSkill ( int ID , int which , int val , bool abs )
{
SetPrimSkill sps ;
sps . id = ID ;
sps . which = which ;
sps . abs = abs ;
sps . val = val ;
sendAndApply ( & sps ) ;
2008-08-13 03:44:31 +03:00
if ( which = = 4 ) //only for exp - hero may level up
2008-08-04 18:56:36 +03:00
{
CGHeroInstance * hero = static_cast < CGHeroInstance * > ( gs - > map - > objects [ ID ] ) ;
if ( hero - > exp > = VLC - > heroh - > reqExp ( hero - > level + 1 ) ) //new level
{
//give prim skill
2008-09-19 15:09:15 +03:00
tlog5 < < hero - > name < < " got level " < < hero - > level < < std : : endl ;
2008-08-04 18:56:36 +03:00
int r = rand ( ) % 100 , pom = 0 , x = 0 ;
int std : : pair < int , int > : : * g = ( hero - > level > 9 ) ? ( & std : : pair < int , int > : : second ) : ( & std : : pair < int , int > : : first ) ;
for ( ; x < PRIMARY_SKILLS ; x + + )
{
pom + = hero - > type - > heroClass - > primChance [ x ] . * g ;
if ( r < pom )
break ;
}
2008-09-19 15:09:15 +03:00
tlog5 < < " Bohater dostaje umiejetnosc pierwszorzedna " < < x < < " (wynik losowania " < < r < < " ) " < < std : : endl ;
2008-08-04 18:56:36 +03:00
SetPrimSkill sps ;
sps . id = ID ;
sps . which = x ;
sps . abs = false ;
sps . val = 1 ;
sendAndApply ( & sps ) ;
2008-08-13 03:44:31 +03:00
HeroLevelUp hlu ;
hlu . heroid = ID ;
hlu . primskill = x ;
hlu . level = hero - > level + 1 ;
2008-08-04 18:56:36 +03:00
2008-08-13 03:44:31 +03:00
//picking sec. skills for choice
2008-08-04 18:56:36 +03:00
std : : set < int > basicAndAdv , expert , none ;
for ( int i = 0 ; i < SKILL_QUANTITY ; i + + ) none . insert ( i ) ;
for ( unsigned i = 0 ; i < hero - > secSkills . size ( ) ; i + + )
{
2008-09-18 17:18:08 +03:00
if ( hero - > secSkills [ i ] . second < 3 )
2008-08-04 18:56:36 +03:00
basicAndAdv . insert ( hero - > secSkills [ i ] . first ) ;
else
expert . insert ( hero - > secSkills [ i ] . first ) ;
none . erase ( hero - > secSkills [ i ] . first ) ;
}
if ( hero - > secSkills . size ( ) < hero - > type - > heroClass - > skillLimit ) //free skill slot
{
2008-08-13 03:44:31 +03:00
hlu . skills . push_back ( hero - > type - > heroClass - > chooseSecSkill ( none ) ) ; //new skill
2008-08-04 18:56:36 +03:00
}
else
{
int s = hero - > type - > heroClass - > chooseSecSkill ( basicAndAdv ) ;
2008-08-13 03:44:31 +03:00
hlu . skills . push_back ( s ) ;
2008-08-04 18:56:36 +03:00
basicAndAdv . erase ( s ) ;
}
if ( basicAndAdv . size ( ) )
{
2008-08-13 03:44:31 +03:00
hlu . skills . push_back ( hero - > type - > heroClass - > chooseSecSkill ( basicAndAdv ) ) ; //new skill
2008-08-04 18:56:36 +03:00
}
else if ( hero - > secSkills . size ( ) < hero - > type - > heroClass - > skillLimit )
{
2008-08-13 03:44:31 +03:00
hlu . skills . push_back ( hero - > type - > heroClass - > chooseSecSkill ( none ) ) ; //new skill
2008-08-04 18:56:36 +03:00
}
2008-08-17 17:09:30 +03:00
boost : : function < void ( ui32 ) > callback = boost : : function < void ( ui32 ) > ( boost : : bind ( callWith < ui16 > , hlu . skills , boost : : function < void ( ui16 ) > ( boost : : bind ( & CGameHandler : : changeSecSkill , this , ID , _1 , 1 , 0 ) ) , _1 ) ) ;
applyAndAsk ( & hlu , hero - > tempOwner , callback ) ; //call changeSecSkill with appropriate args when client responds
2008-08-04 18:56:36 +03:00
}
}
}
2008-09-20 21:30:37 +03:00
CCreatureSet takeCasualties ( int color , const CCreatureSet & set , BattleInfo * bat )
{
CCreatureSet ret ( set ) ;
for ( int i = 0 ; i < bat - > stacks . size ( ) ; i + + )
{
CStack * st = bat - > stacks [ i ] ;
if ( st - > owner = = color & & vstd : : contains ( set . slots , st - > slot ) & & st - > amount < set . slots . find ( st - > slot ) - > second . second )
{
if ( st - > alive ( ) )
ret . slots [ st - > slot ] . second = st - > amount ;
else
ret . slots . erase ( st - > slot ) ;
}
}
return ret ;
}
2008-09-12 11:51:46 +03:00
void CGameHandler : : startBattle ( CCreatureSet army1 , CCreatureSet army2 , int3 tile , CGHeroInstance * hero1 , CGHeroInstance * hero2 , boost : : function < void ( BattleResult * ) > cb )
2008-08-04 18:56:36 +03:00
{
BattleInfo * curB = new BattleInfo ;
2008-09-12 11:51:46 +03:00
setupBattle ( curB , tile , army1 , army2 , hero1 , hero2 ) ; //initializes stacks, places creatures on battlefield, blocks and informs player interfaces
2008-08-15 15:11:42 +03:00
NEW_ROUND ;
2008-09-12 11:51:46 +03:00
//TODO: pre-tactic stuff, call scripts etc.
2008-08-04 18:56:36 +03:00
//tactic round
{
NEW_ROUND ;
2008-09-28 16:29:37 +03:00
if ( ( hero1 & & hero1 - > getSecSkillLevel ( 19 ) > 0 ) | |
( hero2 & & hero2 - > getSecSkillLevel ( 19 ) > 0 ) ) //someone has tactics
2008-08-04 18:56:36 +03:00
{
//TODO: tactic round (round -1)
}
}
//main loop
while ( ! battleResult . get ( ) ) //till the end of the battle ;]
{
NEW_ROUND ;
std : : vector < CStack * > & stacks = ( gs - > curB - > stacks ) ;
const BattleInfo & curB = * gs - > curB ;
//stack loop
2008-11-15 17:26:08 +02:00
CStack * next ;
while ( ! battleResult . get ( ) & & ( next = gs - > curB - > getNextStack ( ) ) )
2008-08-04 18:56:36 +03:00
{
2009-02-05 11:49:45 +02:00
next - > state - = WAITING ; //if stack was waiting it'll now make move, so it won't be "waiting" anymore
//check for bad morale => freeze
if ( next - > Morale ( ) < 0 )
{
if ( rand ( ) % 24 < ( - next - > Morale ( ) ) * 2 )
{
//unit loses its turn - empty freeze action
BattleAction ba ;
ba . actionType = 11 ;
ba . additionalInfo = 1 ;
ba . side = ! next - > attackerOwned ;
ba . stackNumber = next - > ID ;
sendAndApply ( & StartAction ( ba ) ) ;
sendDataToClients ( ui16 ( 3008 ) ) ;
checkForBattleEnd ( stacks ) ; //check if this "action" ended the battle (not likely but who knows...)
continue ;
}
}
askInterfaceForMove :
//ask interface and wait for answer
{
BattleSetActiveStack sas ;
sas . stack = next - > ID ;
sendAndApply ( & sas ) ;
boost : : unique_lock < boost : : mutex > lock ( battleMadeAction . mx ) ;
while ( ! battleMadeAction . data & & ! battleResult . get ( ) ) //active stack hasn't made its action and battle is still going
battleMadeAction . cond . wait ( lock ) ;
battleMadeAction . data = false ;
}
//we're after action, all results applied
2008-09-12 11:51:46 +03:00
checkForBattleEnd ( stacks ) ; //check if this action ended the battle
2009-02-05 11:49:45 +02:00
//check for good morale
if ( ! vstd : : contains ( next - > state , HAD_MORALE ) //only one extra move per turn possible
& & ! vstd : : contains ( next - > state , DEFENDING )
& & ! vstd : : contains ( next - > state , WAITING )
& & next - > alive ( )
& & next - > Morale ( ) > 0
)
if ( rand ( ) % 24 < next - > Morale ( ) ) //this stack hasn't got morale this turn
goto askInterfaceForMove ; //move this stack once more
2008-09-08 14:32:16 +03:00
}
2008-08-04 18:56:36 +03:00
}
2008-08-13 03:44:31 +03:00
//unblock engaged players
if ( hero1 - > tempOwner < PLAYER_LIMIT )
states . setFlag ( hero1 - > tempOwner , & PlayerStatus : : engagedIntoBattle , false ) ;
if ( hero2 & & hero2 - > tempOwner < PLAYER_LIMIT )
2008-09-20 21:30:37 +03:00
states . setFlag ( hero2 - > tempOwner , & PlayerStatus : : engagedIntoBattle , false ) ;
//casualties among heroes armies
SetGarrisons sg ;
if ( hero1 )
sg . garrs [ hero1 - > id ] = takeCasualties ( hero1 - > tempOwner , hero1 - > army , gs - > curB ) ;
if ( hero2 )
sg . garrs [ hero2 - > id ] = takeCasualties ( hero2 - > tempOwner , hero2 - > army , gs - > curB ) ;
sendAndApply ( & sg ) ;
2008-08-13 03:44:31 +03:00
2008-08-04 18:56:36 +03:00
//end battle, remove all info, free memory
2008-09-29 13:16:02 +03:00
giveExp ( * battleResult . data ) ;
2008-08-04 18:56:36 +03:00
sendAndApply ( battleResult . data ) ;
2008-09-12 11:51:46 +03:00
if ( cb )
cb ( battleResult . data ) ;
2008-09-20 21:30:37 +03:00
//if one hero has lost we will erase him
if ( battleResult . data - > winner ! = 0 & & hero1 )
{
RemoveObject ro ( hero1 - > id ) ;
sendAndApply ( & ro ) ;
}
if ( battleResult . data - > winner ! = 1 & & hero2 )
{
RemoveObject ro ( hero2 - > id ) ;
sendAndApply ( & ro ) ;
}
2008-09-29 13:16:02 +03:00
//give exp
if ( battleResult . data - > exp [ 0 ] & & hero1 )
changePrimSkill ( hero1 - > id , 4 , battleResult . data - > exp [ 0 ] ) ;
if ( battleResult . data - > exp [ 1 ] & & hero2 )
changePrimSkill ( hero2 - > id , 4 , battleResult . data - > exp [ 1 ] ) ;
2008-08-04 18:56:36 +03:00
delete battleResult . data ;
2008-09-20 21:30:37 +03:00
2008-08-04 18:56:36 +03:00
}
2008-10-18 14:41:24 +03:00
void CGameHandler : : prepareAttacked ( BattleStackAttacked & bsa , CStack * def )
{
bsa . killedAmount = bsa . damageAmount / def - > creature - > hitPoints ;
unsigned damageFirst = bsa . damageAmount % def - > creature - > hitPoints ;
2008-08-09 02:02:32 +03:00
if ( def - > firstHPleft < = damageFirst )
{
2008-10-18 14:41:24 +03:00
bsa . killedAmount + + ;
bsa . newHP = def - > firstHPleft + def - > creature - > hitPoints - damageFirst ;
2008-08-09 02:02:32 +03:00
}
else
{
2008-10-18 14:41:24 +03:00
bsa . newHP = def - > firstHPleft - damageFirst ;
2008-08-09 02:02:32 +03:00
}
2008-08-04 18:56:36 +03:00
2008-10-18 14:41:24 +03:00
if ( def - > amount < = bsa . killedAmount ) //stack killed
2008-08-09 02:02:32 +03:00
{
2008-10-18 14:41:24 +03:00
bsa . newAmount = 0 ;
bsa . flags | = 1 ;
bsa . killedAmount = def - > amount ; //we cannot kill more creatures than we have
2008-08-09 02:02:32 +03:00
}
else
{
2008-10-18 14:41:24 +03:00
bsa . newAmount = def - > amount - bsa . killedAmount ;
2008-08-09 02:02:32 +03:00
}
}
2008-10-18 14:41:24 +03:00
void CGameHandler : : prepareAttack ( BattleAttack & bat , CStack * att , CStack * def )
{
bat . stackAttacking = att - > ID ;
bat . bsa . stackAttacked = def - > ID ;
bat . bsa . damageAmount = BattleInfo : : calculateDmg ( att , def , gs - > getHero ( att - > attackerOwned ? gs - > curB - > hero1 : gs - > curB - > hero2 ) , gs - > getHero ( def - > attackerOwned ? gs - > curB - > hero1 : gs - > curB - > hero2 ) , bat . shot ( ) ) ; //counting dealt damage
2009-02-05 11:49:45 +02:00
if ( att - > Luck ( ) > 0 & & rand ( ) % 24 < att - > Luck ( ) )
{
bat . bsa . damageAmount * = 2 ;
bat . bsa . flags | = 4 ;
}
2008-10-18 14:41:24 +03:00
prepareAttacked ( bat . bsa , def ) ;
}
2008-07-25 20:28:28 +03:00
void CGameHandler : : handleConnection ( std : : set < int > players , CConnection & c )
{
2008-07-27 20:07:37 +03:00
try
2008-07-25 20:28:28 +03:00
{
2008-07-27 20:07:37 +03:00
ui16 pom ;
2008-08-04 12:05:52 +03:00
while ( ! end2 )
2008-07-25 20:28:28 +03:00
{
2008-07-27 20:07:37 +03:00
c > > pom ;
2008-08-04 12:05:52 +03:00
bool blockvis = false ;
2008-07-27 20:07:37 +03:00
switch ( pom )
{
2008-11-16 03:06:15 +02:00
case 98 :
{
std : : string fname ;
2009-01-06 20:42:20 +02:00
Mapa * mapa ;
2008-11-16 03:06:15 +02:00
c > > fname ;
2009-01-06 20:42:20 +02:00
{
2009-02-01 16:11:41 +02:00
sendMessageTo ( c , " Serializing game info... " ) ;
2009-01-11 00:08:18 +02:00
CSaveFile save ( std : : string ( " Games " ) + PATHSEPARATOR + fname + " .vlgm1 " ) ;
char hlp [ 8 ] = " VCMISVG " ;
2009-02-01 16:11:41 +02:00
save < < hlp < < version < < static_cast < CMapHeader & > ( * gs - > map ) < < gs - > scenarioOps - > difficulty < < * VLC < < gs ;
2009-01-06 20:42:20 +02:00
}
{
2009-02-01 16:11:41 +02:00
sendMessageTo ( c , " Serializing server info... " ) ;
2009-01-11 00:08:18 +02:00
CSaveFile save ( std : : string ( " Games " ) + PATHSEPARATOR + fname + " .vsgm1 " ) ;
save < < * this ;
2009-01-06 20:42:20 +02:00
}
2009-02-01 16:11:41 +02:00
sendMessageTo ( c , " Game has been succesfully saved! " ) ;
2008-11-16 03:06:15 +02:00
break ;
}
2008-09-17 13:18:22 +03:00
case 99 : //end!
{
2008-09-19 11:16:19 +03:00
tlog0 < < " We have been requested to close. \n " ;
2008-09-17 13:18:22 +03:00
exit ( 0 ) ;
}
2008-07-28 15:44:08 +03:00
case 100 : //my interface ended its turn
{
2008-08-13 03:44:31 +03:00
states . setFlag ( gs - > currentPlayer , & PlayerStatus : : makingTurn , false ) ;
2008-07-28 15:44:08 +03:00
break ;
}
2008-09-20 21:30:37 +03:00
case 500 : //dismiss hero
2008-08-02 00:41:38 +03:00
{
si32 id ;
c > > id ;
2008-08-13 07:41:11 +03:00
RemoveObject rh ( id ) ;
2008-08-02 00:41:38 +03:00
sendAndApply ( & rh ) ;
break ;
}
2008-07-28 15:44:08 +03:00
case 501 : //interface wants to move hero
{
int3 start , end ;
si32 id ;
c > > id > > start > > end ;
2008-09-23 13:58:54 +03:00
tlog5 < < " Interface wants to move hero " < < id < < " from " < < start < < " to " < < end < < std : : endl ;
2008-07-28 15:44:08 +03:00
int3 hmpos = end + int3 ( - 1 , 0 , 0 ) ;
2008-07-29 22:10:28 +03:00
TerrainTile t = gs - > map - > terrain [ hmpos . x ] [ hmpos . y ] [ hmpos . z ] ;
2008-07-28 15:44:08 +03:00
CGHeroInstance * h = static_cast < CGHeroInstance * > ( gs - > map - > objects [ id ] ) ;
2008-07-30 20:51:19 +03:00
int cost = ( int ) ( ( double ) h - > getTileCost ( t . tertype , t . malle , t . nuine ) * distance ( start , end ) ) ;
2008-07-28 15:44:08 +03:00
TryMoveHero tmh ;
tmh . id = id ;
2008-07-29 12:53:27 +03:00
tmh . start = start ;
2008-07-28 15:44:08 +03:00
tmh . end = end ;
tmh . result = 0 ;
tmh . movePoints = h - > movement ;
2008-10-18 14:41:24 +03:00
if ( ( h - > getOwner ( ) ! = gs - > currentPlayer ) //not turn of that hero
| | ( distance ( start , end ) > = 1.5 ) //tiles are not neighouring
| | ( h - > movement < cost ) //lack of movement points
| | ( t . tertype = = rock ) //rock
| | ( ! h - > canWalkOnSea ( ) & & t . tertype = = water )
| | ( t . blocked & & ! t . visitable ) //tile is blocked andnot visitable
)
2008-07-28 15:44:08 +03:00
goto fail ;
2008-07-29 12:53:27 +03:00
//check if there is blocking visitable object
2008-08-04 12:05:52 +03:00
blockvis = false ;
2008-07-28 15:44:08 +03:00
tmh . movePoints = h - > movement = ( h - > movement - cost ) ; //take move points
BOOST_FOREACH ( CGObjectInstance * obj , t . visitableObjects )
{
if ( obj - > blockVisit )
{
blockvis = true ;
break ;
}
}
2008-07-29 12:53:27 +03:00
//we start moving
2008-07-28 15:44:08 +03:00
if ( blockvis ) //interaction with blocking object (like resources)
{
2008-07-30 20:51:19 +03:00
sendAndApply ( & tmh ) ; //failed to move to that tile but we visit object
2008-07-28 15:44:08 +03:00
BOOST_FOREACH ( CGObjectInstance * obj , t . visitableObjects )
{
if ( obj - > blockVisit )
{
2008-07-30 20:51:19 +03:00
//if(gs->checkFunc(obj->ID,"heroVisit")) //script function
// gs->objscr[obj->ID]["heroVisit"]->onHeroVisit(obj,h->subID);
2008-12-22 19:48:41 +02:00
//if(obj->state) //hard-coded function
obj - > onHeroVisit ( h ) ;
2008-07-28 15:44:08 +03:00
}
}
2008-09-23 13:58:54 +03:00
tlog5 < < " Blocing visit at " < < hmpos < < std : : endl ;
2008-07-28 15:44:08 +03:00
break ;
}
else //normal move
{
tmh . result = 1 ;
2008-08-13 12:28:06 +03:00
BOOST_FOREACH ( CGObjectInstance * obj , gs - > map - > terrain [ start . x - 1 ] [ start . y ] [ start . z ] . visitableObjects )
2008-07-28 15:44:08 +03:00
{
//TODO: allow to handle this in script-languages
2008-12-22 19:48:41 +02:00
//if(obj->state) //hard-coded function
obj - > onHeroLeave ( h ) ;
2008-07-28 15:44:08 +03:00
}
2008-09-23 13:58:54 +03:00
tmh . fowRevealed = gs - > tilesToReveal ( h - > getPosition ( false ) , h - > getSightDistance ( ) , h - > tempOwner ) ;
2008-07-30 20:51:19 +03:00
sendAndApply ( & tmh ) ;
2008-09-23 13:58:54 +03:00
tlog5 < < " Moved to " < < tmh . end < < std : : endl ;
2008-07-28 15:44:08 +03:00
2008-07-30 20:51:19 +03:00
BOOST_FOREACH ( CGObjectInstance * obj , t . visitableObjects ) //call objects if they are visited
2008-07-28 15:44:08 +03:00
{
2008-07-30 20:51:19 +03:00
//if(gs->checkFunc(obj->ID,"heroVisit")) //script function
// gs->objscr[obj->ID]["heroVisit"]->onHeroVisit(obj,h->subID);
2008-12-22 19:48:41 +02:00
//if(obj->state) //hard-coded function
obj - > onHeroVisit ( h ) ;
2008-07-28 15:44:08 +03:00
}
}
2008-09-23 13:58:54 +03:00
tlog5 < < " Movement end! \n " ;
2008-07-28 15:44:08 +03:00
break ;
fail :
2008-09-23 13:58:54 +03:00
tlog2 < < " Movement failed to " < < tmh . end < < std : : endl ;
2008-07-30 20:51:19 +03:00
sendAndApply ( & tmh ) ;
2008-07-28 15:44:08 +03:00
break ;
}
2008-07-31 16:21:42 +03:00
case 502 : //swap creatures in garrison
{
ui8 what , p1 , p2 ; si32 id1 , id2 ;
c > > what > > id1 > > p1 > > id2 > > p2 ;
CArmedInstance * s1 = static_cast < CArmedInstance * > ( gs - > map - > objects [ id1 ] ) ,
* s2 = static_cast < CArmedInstance * > ( gs - > map - > objects [ id2 ] ) ;
2008-11-15 02:55:19 +02:00
CCreatureSet temp1 = s1 - > army , temp2 = s2 - > army ,
& S1 = temp1 , & S2 = ( s1 ! = s2 ) ? ( temp2 ) : ( temp1 ) ;
2008-07-31 16:21:42 +03:00
if ( what = = 1 ) //swap
{
2008-11-15 02:55:19 +02:00
std : : swap ( S1 . slots [ p1 ] , S2 . slots [ p2 ] ) ;
if ( ! S1 . slots [ p1 ] . second )
S1 . slots . erase ( p1 ) ;
if ( ! S2 . slots [ p2 ] . second )
S2 . slots . erase ( p2 ) ;
2008-07-31 16:21:42 +03:00
}
else if ( what = = 2 ) //merge
{
2008-11-15 02:55:19 +02:00
if ( S1 . slots [ p1 ] . first ! = S2 . slots [ p2 ] . first ) break ; //not same creature
S2 . slots [ p2 ] . second + = S1 . slots [ p1 ] . second ;
S1 . slots . erase ( p1 ) ;
2008-07-31 16:21:42 +03:00
}
else if ( what = = 3 ) //split
{
si32 val ;
c > > val ;
2008-11-15 02:55:19 +02:00
if ( vstd : : contains ( S2 . slots , p2 ) //dest. slot not free
| | ! vstd : : contains ( S1 . slots , p1 ) //no creatures to split
| | S1 . slots [ p1 ] . second < val //not enough creatures
| | val < 1 //val must be positive
)
break ;
S2 . slots [ p2 ] . first = S1 . slots [ p1 ] . first ;
S2 . slots [ p2 ] . second = val ;
S1 . slots [ p1 ] . second - = val ;
if ( ! S1 . slots [ p1 ] . second ) //if we've moved all creatures
S1 . slots . erase ( p1 ) ;
2008-07-31 16:21:42 +03:00
}
2008-11-15 02:55:19 +02:00
if ( ( s1 - > needsLastStack ( ) & & ! S1 . slots . size ( ) ) //it's not allowed to take last stack from hero army!
| | ( s2 - > needsLastStack ( ) & & ! S2 . slots . size ( ) )
)
2008-08-20 22:02:48 +03:00
{
2008-11-15 02:55:19 +02:00
break ; //leave without applying changes to garrison
2008-08-20 22:02:48 +03:00
}
2008-07-31 16:21:42 +03:00
SetGarrisons sg ;
2008-11-15 02:55:19 +02:00
sg . garrs [ id1 ] = S1 ;
2008-07-31 16:21:42 +03:00
if ( s1 ! = s2 )
2008-11-15 02:55:19 +02:00
sg . garrs [ id2 ] = S2 ;
2008-07-31 16:21:42 +03:00
sendAndApply ( & sg ) ;
2008-08-01 14:21:15 +03:00
break ;
}
2008-09-20 21:30:37 +03:00
case 503 : //disband creature
2008-08-01 14:21:15 +03:00
{
si32 id ;
ui8 pos ;
c > > id > > pos ;
CArmedInstance * s1 = static_cast < CArmedInstance * > ( gs - > map - > objects [ id ] ) ;
s1 - > army . slots . erase ( pos ) ;
SetGarrisons sg ;
sg . garrs [ id ] = s1 - > army ;
sendAndApply ( & sg ) ;
break ;
}
2008-09-20 21:30:37 +03:00
case 504 : //build structure
2008-08-01 14:21:15 +03:00
{
si32 tid , bid ;
c > > tid > > bid ;
CGTownInstance * t = static_cast < CGTownInstance * > ( gs - > map - > objects [ tid ] ) ;
CBuilding * b = VLC - > buildh - > buildings [ t - > subID ] [ bid ] ;
for ( int i = 0 ; i < RESOURCE_QUANTITY ; i + + )
if ( b - > resources [ i ] > gs - > players [ t - > tempOwner ] . resources [ i ] )
break ; //no res
2008-09-23 13:58:54 +03:00
for ( std : : set < int > : : iterator ri = VLC - > townh - > requirements [ t - > subID ] [ bid ] . begin ( ) ;
ri ! = VLC - > townh - > requirements [ t - > subID ] [ bid ] . end ( ) ;
ri + + )
{
if ( ! vstd : : contains ( t - > builtBuildings , * ri ) )
break ; //lack of requirements - cannot build
}
if ( vstd : : contains ( t - > forbiddenBuildings , bid ) )
break ; //this building is forbidden
2008-08-01 14:21:15 +03:00
NewStructures ns ;
ns . tid = tid ;
if ( bid > 36 ) //upg dwelling
{
if ( t - > getHordeLevel ( 0 ) = = ( bid - 37 ) )
ns . bid . insert ( 19 ) ;
else if ( t - > getHordeLevel ( 1 ) = = ( bid - 37 ) )
ns . bid . insert ( 25 ) ;
}
else if ( bid > = 30 ) //bas. dwelling
{
2008-08-10 07:46:16 +03:00
SetAvailableCreatures ssi ;
2008-08-01 14:21:15 +03:00
ssi . tid = tid ;
2008-08-10 07:46:16 +03:00
ssi . creatures = t - > strInfo . creatures ;
ssi . creatures [ bid - 30 ] = VLC - > creh - > creatures [ t - > town - > basicCreatures [ bid - 30 ] ] . growth ;
2008-08-01 14:21:15 +03:00
sendAndApply ( & ssi ) ;
}
ns . bid . insert ( bid ) ;
ns . builded = t - > builded + 1 ;
sendAndApply ( & ns ) ;
SetResources sr ;
sr . player = t - > tempOwner ;
sr . res = gs - > players [ t - > tempOwner ] . resources ;
for ( int i = 0 ; i < 7 ; i + + )
sr . res [ i ] - = b - > resources [ i ] ;
sendAndApply ( & sr ) ;
2008-09-12 11:51:46 +03:00
if ( bid < 5 ) //it's mage guild
{
if ( t - > visitingHero )
giveSpells ( t , t - > visitingHero ) ;
if ( t - > garrisonHero )
giveSpells ( t , t - > garrisonHero ) ;
}
2008-08-10 07:46:16 +03:00
break ;
}
case 506 : //recruit creature
{
si32 objid , ser = - 1 ; //ser - used dwelling level
ui32 crid , cram ; //recruited creature id and amount
c > > objid > > crid > > cram ;
CGTownInstance * t = static_cast < CGTownInstance * > ( gs - > map - > objects [ objid ] ) ;
//verify
bool found = false ;
typedef std : : pair < const int , int > Parka ;
for ( std : : map < si32 , ui32 > : : iterator av = t - > strInfo . creatures . begin ( ) ; av ! = t - > strInfo . creatures . end ( ) ; av + + )
{
if ( ( found = ( crid = = t - > town - > basicCreatures [ av - > first ] ) ) //creature is available among basic cretures
| | ( found = ( crid = = t - > town - > upgradedCreatures [ av - > first ] ) ) ) //creature is available among upgraded cretures
{
cram = std : : min ( cram , av - > second ) ; //reduce recruited amount up to available amount
ser = av - > first ;
break ;
}
}
int slot = t - > army . getSlotFor ( crid ) ;
if ( ! found | | //no such creature
cram > VLC - > creh - > creatures [ crid ] . maxAmount ( gs - > players [ t - > tempOwner ] . resources ) | | //lack of resources
cram < = 0 | |
slot < 0 )
break ;
//recruit
SetResources sr ;
sr . player = t - > tempOwner ;
for ( int i = 0 ; i < RESOURCE_QUANTITY ; i + + )
sr . res [ i ] = gs - > players [ t - > tempOwner ] . resources [ i ] - ( VLC - > creh - > creatures [ crid ] . cost [ i ] * cram ) ;
SetAvailableCreatures sac ;
sac . tid = objid ;
sac . creatures = t - > strInfo . creatures ;
sac . creatures [ ser ] - = cram ;
SetGarrisons sg ;
sg . garrs [ objid ] = t - > army ;
if ( sg . garrs [ objid ] . slots . find ( slot ) = = sg . garrs [ objid ] . slots . end ( ) ) //take a free slot
{
sg . garrs [ objid ] . slots [ slot ] = std : : make_pair ( crid , cram ) ;
}
else //add creatures to a already existing stack
{
sg . garrs [ objid ] . slots [ slot ] . second + = cram ;
}
sendAndApply ( & sr ) ;
sendAndApply ( & sac ) ;
sendAndApply ( & sg ) ;
2008-08-04 18:56:36 +03:00
break ;
}
2008-08-15 15:11:42 +03:00
case 507 : //upgrade creature
{
ui32 objid , upgID ;
ui8 pos ;
c > > objid > > pos > > upgID ;
CArmedInstance * obj = static_cast < CArmedInstance * > ( gs - > map - > objects [ objid ] ) ;
UpgradeInfo ui = gs - > getUpgradeInfo ( obj , pos ) ;
int player = obj - > tempOwner ;
int crQuantity = obj - > army . slots [ pos ] . second ;
//check if upgrade is possible
if ( ui . oldID < 0 | | ! vstd : : contains ( ui . newID , upgID ) )
break ;
//check if player has enough resources
for ( int i = 0 ; i < ui . cost . size ( ) ; i + + )
{
for ( std : : set < std : : pair < int , int > > : : iterator j = ui . cost [ i ] . begin ( ) ; j ! = ui . cost [ i ] . end ( ) ; j + + )
{
if ( gs - > players [ player ] . resources [ j - > first ] < j - > second * crQuantity )
goto upgend ;
}
}
//take resources
for ( int i = 0 ; i < ui . cost . size ( ) ; i + + )
{
for ( std : : set < std : : pair < int , int > > : : iterator j = ui . cost [ i ] . begin ( ) ; j ! = ui . cost [ i ] . end ( ) ; j + + )
{
SetResource sr ;
sr . player = player ;
sr . resid = j - > first ;
sr . val = gs - > players [ player ] . resources [ j - > first ] - j - > second * crQuantity ;
sendAndApply ( & sr ) ;
}
}
{
//upgrade creature
SetGarrisons sg ;
sg . garrs [ objid ] = obj - > army ;
sg . garrs [ objid ] . slots [ pos ] . first = upgID ;
sendAndApply ( & sg ) ;
}
upgend :
break ;
}
2008-08-16 11:47:41 +03:00
case 508 : //garrison swap
{
si32 tid ;
c > > tid ;
CGTownInstance * town = gs - > getTown ( tid ) ;
if ( ! town - > garrisonHero & & town - > visitingHero ) //visiting => garrison, merge armies
{
CCreatureSet csn = town - > visitingHero - > army , cso = town - > army ;
while ( ! cso . slots . empty ( ) ) //while there are unmoved creatures
{
2008-08-20 09:57:53 +03:00
int pos = csn . getSlotFor ( cso . slots . begin ( ) - > second . first ) ;
2008-08-16 11:47:41 +03:00
if ( pos < 0 )
goto handleConEnd ;
if ( csn . slots . find ( pos ) ! = csn . slots . end ( ) ) //add creatures to the existing stack
{
csn . slots [ pos ] . second + = cso . slots . begin ( ) - > second . second ;
}
else //move stack on the free pos
{
csn . slots [ pos ] . first = cso . slots . begin ( ) - > second . first ;
csn . slots [ pos ] . second = cso . slots . begin ( ) - > second . second ;
}
cso . slots . erase ( cso . slots . begin ( ) ) ;
}
SetGarrisons sg ;
sg . garrs [ town - > visitingHero - > id ] = csn ;
sg . garrs [ town - > id ] = csn ;
sendAndApply ( & sg ) ;
SetHeroesInTown intown ;
intown . tid = tid ;
intown . visiting = - 1 ;
intown . garrison = town - > visitingHero - > id ;
sendAndApply ( & intown ) ;
}
else if ( town - > garrisonHero & & ! town - > visitingHero ) //move hero out of the garrison
{
SetHeroesInTown intown ;
intown . tid = tid ;
intown . garrison = - 1 ;
intown . visiting = town - > garrisonHero - > id ;
sendAndApply ( & intown ) ;
2008-08-25 13:25:16 +03:00
//town will be empty
SetGarrisons sg ;
sg . garrs [ tid ] = CCreatureSet ( ) ;
sendAndApply ( & sg ) ;
2008-08-16 11:47:41 +03:00
}
else if ( town - > garrisonHero & & town - > visitingHero ) //swap visiting and garrison hero
{
SetGarrisons sg ;
sg . garrs [ town - > id ] = town - > visitingHero - > army ;
2008-08-25 13:25:16 +03:00
sg . garrs [ town - > garrisonHero - > id ] = town - > garrisonHero - > army ;
//sg.garrs[town->visitingHero->id] = town->visitingHero->army;
2008-08-16 11:47:41 +03:00
SetHeroesInTown intown ;
intown . tid = tid ;
intown . garrison = town - > visitingHero - > id ;
intown . visiting = town - > garrisonHero - > id ;
sendAndApply ( & intown ) ;
2008-08-25 13:25:16 +03:00
sendAndApply ( & sg ) ;
2008-08-16 11:47:41 +03:00
}
else
{
2008-09-19 15:09:15 +03:00
tlog3 < < " Warning, wrong garrison swap command for " < < tid < < std : : endl ;
2008-08-16 11:47:41 +03:00
}
break ;
}
2008-08-25 13:25:16 +03:00
case 509 : //swap artifacts
2008-08-20 22:02:48 +03:00
{
si32 hid1 , hid2 ;
ui16 slot1 , slot2 ;
c > > hid1 > > slot1 > > hid2 > > slot2 ;
CGHeroInstance * h1 = gs - > getHero ( hid1 ) , * h2 = gs - > getHero ( hid2 ) ;
if ( ( distance ( h1 - > pos , h2 - > pos ) > 1.0 ) | | ( h1 - > tempOwner ! = h2 - > tempOwner ) )
break ;
int a1 = h1 - > getArtAtPos ( slot1 ) , a2 = h2 - > getArtAtPos ( slot2 ) ;
h2 - > setArtAtPos ( slot2 , a1 ) ;
h1 - > setArtAtPos ( slot1 , a2 ) ;
SetHeroArtifacts sha ;
sha . hid = hid1 ;
sha . artifacts = h1 - > artifacts ;
sha . artifWorn = h1 - > artifWorn ;
sendAndApply ( & sha ) ;
if ( hid1 ! = hid2 )
{
sha . hid = hid2 ;
sha . artifacts = h2 - > artifacts ;
sha . artifWorn = h2 - > artifWorn ;
sendAndApply ( & sha ) ;
}
2008-08-25 13:25:16 +03:00
break ;
}
case 510 : //buy artifact
{
ui32 hid ;
si32 aid , bid ;
c > > hid > > aid ;
CGHeroInstance * hero = gs - > getHero ( hid ) ;
CGTownInstance * town = hero - > visitedTown ;
2008-09-12 11:51:46 +03:00
if ( aid = = 0 ) //spellbok
2008-08-25 13:25:16 +03:00
{
if ( ! vstd : : contains ( town - > builtBuildings , si32 ( 0 ) ) )
break ;
SetResource sr ;
sr . player = hero - > tempOwner ;
sr . resid = 6 ;
sr . val = gs - > players [ hero - > tempOwner ] . resources [ 6 ] - 500 ;
sendAndApply ( & sr ) ;
SetHeroArtifacts sha ;
sha . hid = hid ;
sha . artifacts = hero - > artifacts ;
sha . artifWorn = hero - > artifWorn ;
sha . artifWorn [ 17 ] = 0 ;
sendAndApply ( & sha ) ;
2008-09-12 11:51:46 +03:00
giveSpells ( town , hero ) ;
2008-08-25 13:25:16 +03:00
}
2008-08-27 13:19:18 +03:00
else if ( aid < 7 & & aid > 3 ) //war machine
{
int price = VLC - > arth - > artifacts [ aid ] . price ;
if ( vstd : : contains ( hero - > artifWorn , ui16 ( 9 + aid ) ) //hero already has this machine
| | ! vstd : : contains ( town - > builtBuildings , si32 ( 16 ) ) //no blackismith
| | gs - > players [ hero - > tempOwner ] . resources [ 6 ] < price //no gold
| | town - > town - > warMachine ! = aid ) //this machine is not available here (//TODO: support ballista yard in stronghold)
{
break ;
}
SetResource sr ;
sr . player = hero - > tempOwner ;
sr . resid = 6 ;
sr . val = gs - > players [ hero - > tempOwner ] . resources [ 6 ] - price ;
sendAndApply ( & sr ) ;
SetHeroArtifacts sha ;
sha . hid = hid ;
sha . artifacts = hero - > artifacts ;
sha . artifWorn = hero - > artifWorn ;
sha . artifWorn [ 9 + aid ] = aid ;
sendAndApply ( & sha ) ;
}
2008-09-07 06:38:37 +03:00
break ;
}
case 511 : //trade at marketplace
{
ui8 player ;
ui32 mode , id1 , id2 , val ;
c > > player > > mode > > id1 > > id2 > > val ;
val = std : : min ( si32 ( val ) , gs - > players [ player ] . resources [ id1 ] ) ;
double uzysk = ( double ) gs - > resVals [ id1 ] * val * gs - > getMarketEfficiency ( player ) ;
uzysk / = gs - > resVals [ id2 ] ;
SetResource sr ;
sr . player = player ;
sr . resid = id1 ;
sr . val = gs - > players [ player ] . resources [ id1 ] - val ;
sendAndApply ( & sr ) ;
sr . resid = id2 ;
sr . val = gs - > players [ player ] . resources [ id2 ] + ( int ) uzysk ;
sendAndApply ( & sr ) ;
2008-09-18 16:54:54 +03:00
break ;
}
case 512 :
{
si32 hid ;
ui8 formation ;
c > > hid > > formation ;
2008-09-19 11:16:19 +03:00
gs - > getHero ( hid ) - > army . formation = formation ;
2008-08-25 13:25:16 +03:00
break ;
2008-08-20 22:02:48 +03:00
}
2008-10-19 02:20:48 +03:00
case 513 :
{
std : : string message ;
c > > message ;
bool cheated = true ;
sendDataToClients ( ui16 ( 513 ) ) ;
sendDataToClients ( ui8 ( * players . begin ( ) ) ) ;
sendDataToClients ( message ) ;
if ( message = = " vcmiistari " ) //give all spells and 999 mana
{
SetMana sm ;
ChangeSpells cs ;
cs . learn = 1 ;
for ( int i = 0 ; i < VLC - > spellh - > spells . size ( ) ; i + + )
cs . spells . insert ( i ) ;
sm . hid = cs . hid = gs - > players [ * players . begin ( ) ] . currentSelection ;
sm . val = 999 ;
if ( gs - > getHero ( cs . hid ) )
{
sendAndApply ( & cs ) ;
sendAndApply ( & sm ) ;
}
}
else if ( message = = " vcmiainur " ) //gives 5 archangels into each slot
{
SetGarrisons sg ;
CGHeroInstance * hero = gs - > getHero ( gs - > players [ * players . begin ( ) ] . currentSelection ) ;
if ( ! hero ) break ;
sg . garrs [ hero - > id ] = hero - > army ;
for ( int i = 0 ; i < 7 ; i + + )
if ( ! vstd : : contains ( sg . garrs [ hero - > id ] . slots , i ) )
sg . garrs [ hero - > id ] . slots [ i ] = std : : pair < ui32 , si32 > ( 13 , 5 ) ;
sendAndApply ( & sg ) ;
}
else if ( message = = " vcmiangband " ) //gives 10 black knightinto each slot
{
SetGarrisons sg ;
CGHeroInstance * hero = gs - > getHero ( gs - > players [ * players . begin ( ) ] . currentSelection ) ;
if ( ! hero ) break ;
sg . garrs [ hero - > id ] = hero - > army ;
for ( int i = 0 ; i < 7 ; i + + )
if ( ! vstd : : contains ( sg . garrs [ hero - > id ] . slots , i ) )
sg . garrs [ hero - > id ] . slots [ i ] = std : : pair < ui32 , si32 > ( 66 , 10 ) ;
sendAndApply ( & sg ) ;
}
else if ( message = = " vcminoldor " ) //all war machines
{
CGHeroInstance * hero = gs - > getHero ( gs - > players [ * players . begin ( ) ] . currentSelection ) ;
if ( ! hero ) break ;
SetHeroArtifacts sha ;
sha . hid = hero - > id ;
sha . artifacts = hero - > artifacts ;
sha . artifWorn = hero - > artifWorn ;
sha . artifWorn [ 13 ] = 4 ;
sha . artifWorn [ 14 ] = 5 ;
sha . artifWorn [ 15 ] = 6 ;
sendAndApply ( & sha ) ;
}
else if ( message = = " vcminahar " ) //1000000 movement points
{
CGHeroInstance * hero = gs - > getHero ( gs - > players [ * players . begin ( ) ] . currentSelection ) ;
if ( ! hero ) break ;
SetMovePoints smp ;
smp . hid = hero - > id ;
smp . val = 1000000 ;
sendAndApply ( & smp ) ;
}
else if ( message = = " vcmiformenos " ) //give resources
{
SetResources sr ;
sr . player = * players . begin ( ) ;
sr . res = gs - > players [ sr . player ] . resources ;
for ( int i = 0 ; i < 7 ; i + + )
sr . res [ i ] + = 100 ;
sr . res [ 6 ] + = 19900 ;
sendAndApply ( & sr ) ;
}
else if ( message = = " vcmieagles " ) //reveal FoW
{
FoWChange fc ;
fc . player = * players . begin ( ) ;
for ( int i = 0 ; i < gs - > map - > width ; i + + )
for ( int j = 0 ; j < gs - > map - > height ; j + + )
for ( int k = 0 ; k < gs - > map - > twoLevel + 1 ; k + + )
if ( ! gs - > players [ fc . player ] . fogOfWarMap [ i ] [ j ] [ k ] )
fc . tiles . insert ( int3 ( i , j , k ) ) ;
sendAndApply ( & fc ) ;
}
2008-11-01 00:41:22 +02:00
else if ( message = = " vcmiglorfindel " )
{
CGHeroInstance * hero = gs - > getHero ( gs - > players [ * players . begin ( ) ] . currentSelection ) ;
changePrimSkill ( hero - > id , 4 , VLC - > heroh - > reqExp ( hero - > level + 1 ) - VLC - > heroh - > reqExp ( hero - > level ) ) ;
}
2008-10-19 02:20:48 +03:00
else
cheated = false ;
if ( cheated )
{
message = " CHEATER!!! " ;
sendDataToClients ( ui16 ( 513 ) ) ;
sendDataToClients ( ui8 ( * players . begin ( ) ) ) ;
sendDataToClients ( message ) ;
}
break ;
}
case 514 :
{
2008-12-27 03:01:59 +02:00
SetSelection ss ;
c > > ss ;
sendAndApply ( & ss ) ;
2008-10-19 02:20:48 +03:00
break ;
}
2008-10-26 22:58:34 +02:00
case 515 :
{
ui32 tid ;
ui8 hid ;
c > > tid > > hid ;
CGTownInstance * t = gs - > getTown ( tid ) ;
if ( ! vstd : : contains ( players , t - > tempOwner ) //not our town
| | ! vstd : : contains ( t - > builtBuildings , 5 ) //no tavern in the town
| | gs - > players [ t - > tempOwner ] . resources [ 6 ] < 2500 //not enough gold
| | t - > visitingHero //there is visiting hero - no place
| | gs - > players [ t - > tempOwner ] . heroes . size ( ) > 7 //8 hero limit
)
break ;
CGHeroInstance * nh = gs - > players [ t - > tempOwner ] . availableHeroes [ hid ] ;
2008-11-01 00:41:22 +02:00
2008-10-26 22:58:34 +02:00
HeroRecruited hr ;
hr . tid = tid ;
hr . hid = nh - > subID ;
hr . player = t - > tempOwner ;
hr . tile = t - > pos - int3 ( 1 , 0 , 0 ) ;
sendAndApply ( & hr ) ;
2008-11-01 00:41:22 +02:00
SetAvailableHeroes sah ;
( hid ? sah . hid2 : sah . hid1 ) = gs - > hpool . pickHeroFor ( false , t - > tempOwner , t - > town ) - > subID ;
( hid ? sah . hid1 : sah . hid2 ) = gs - > players [ t - > tempOwner ] . availableHeroes [ ! hid ] - > subID ;
sah . player = t - > tempOwner ;
sah . flags = hid + 1 ;
sendAndApply ( & sah ) ;
SetResource sr ;
sr . player = t - > tempOwner ;
sr . resid = 6 ;
sr . val = gs - > players [ t - > tempOwner ] . resources [ 6 ] - 2500 ;
sendAndApply ( & sr ) ;
2008-10-26 22:58:34 +02:00
break ;
}
2008-08-13 03:44:31 +03:00
case 2001 :
{
ui32 qid , answer ;
c > > qid > > answer ;
gsm . lock ( ) ;
2008-08-22 15:21:09 +03:00
CFunctionList < void ( ui32 ) > callb = callbacks [ qid ] ;
2008-08-13 03:44:31 +03:00
callbacks . erase ( qid ) ;
gsm . unlock ( ) ;
callb ( answer ) ;
break ;
}
2008-08-04 18:56:36 +03:00
case 3002 :
2008-09-29 00:01:49 +03:00
{
2008-08-04 18:56:36 +03:00
BattleAction ba ;
c > > ba ;
switch ( ba . actionType )
{
case 2 : //walk
{
2008-09-29 00:01:49 +03:00
sendAndApply ( & StartAction ( ba ) ) ; //start movement
moveStack ( ba . stackNumber , ba . destinationTile ) ; //move
2008-11-15 17:26:08 +02:00
sendDataToClients ( ui16 ( 3008 ) ) ; //end movement
2008-08-04 18:56:36 +03:00
break ;
}
case 3 : //defend
2008-11-15 17:26:08 +02:00
case 8 : //wait
2008-08-04 18:56:36 +03:00
{
2008-11-15 17:26:08 +02:00
sendAndApply ( & StartAction ( ba ) ) ;
sendDataToClients ( ui16 ( 3008 ) ) ;
2008-08-04 18:56:36 +03:00
break ;
}
case 4 : //retreat/flee
{
//TODO: check if fleeing is possible (e.g. enemy may have Shackles of War)
//TODO: calculate casualties
2008-11-15 17:26:08 +02:00
//TODO: remove retreating hero from map and place it in recruitment list
2008-08-04 18:56:36 +03:00
BattleResult * br = new BattleResult ;
br - > result = 1 ;
2008-09-07 18:39:19 +03:00
br - > winner = ! ba . side ; //fleeing side loses
2008-09-09 10:05:02 +03:00
gs - > curB - > calculateCasualties ( br - > casualties ) ;
2008-09-29 13:16:02 +03:00
giveExp ( * br ) ;
2008-08-04 18:56:36 +03:00
battleResult . set ( br ) ;
break ;
}
case 6 : //walk or attack
{
2008-09-29 00:01:49 +03:00
sendAndApply ( & StartAction ( ba ) ) ; //start movement and attack
2008-08-09 02:02:32 +03:00
moveStack ( ba . stackNumber , ba . destinationTile ) ;
CStack * curStack = gs - > curB - > getStack ( ba . stackNumber ) ,
* stackAtEnd = gs - > curB - > getStackT ( ba . additionalInfo ) ;
2009-01-30 16:36:26 +02:00
if ( curStack - > position ! = ba . destinationTile ) //we wasn't able to reach destination tile
{
tlog3 < < " We cannot move this stack to its destination " < < curStack - > creature - > namePl < < std : : endl ;
}
2009-02-03 07:28:05 +02:00
if ( ! stackAtEnd )
2008-11-02 00:32:56 +02:00
{
2009-02-03 07:28:05 +02:00
tlog3 < < " There is no stack on " < < ba . additionalInfo < < " tile (no attack)! " ;
break ;
}
ui16 curpos = curStack - > position ,
enemypos = stackAtEnd - > position ;
if ( ! (
( BattleInfo : : mutualPosition ( curpos , enemypos ) > = 0 ) //front <=> front
| | ( curStack - > creature - > isDoubleWide ( ) //back <=> front
& & BattleInfo : : mutualPosition ( curpos + ( curStack - > attackerOwned ? - 1 : 1 ) , enemypos ) > = 0 )
| | ( stackAtEnd - > creature - > isDoubleWide ( ) //front <=> back
& & BattleInfo : : mutualPosition ( curpos , enemypos + ( stackAtEnd - > attackerOwned ? - 1 : 1 ) ) > = 0 )
| | ( stackAtEnd - > creature - > isDoubleWide ( ) & & curStack - > creature - > isDoubleWide ( ) //back <=> back
& & BattleInfo : : mutualPosition ( curpos + ( curStack - > attackerOwned ? - 1 : 1 ) , enemypos + ( stackAtEnd - > attackerOwned ? - 1 : 1 ) ) > = 0 )
)
)
{
tlog3 < < " Attack cannot be performed! " ;
2008-11-02 00:32:56 +02:00
sendDataToClients ( ui16 ( 3008 ) ) ; //end movement and attack
break ;
}
2008-08-09 02:02:32 +03:00
2009-02-03 07:28:05 +02:00
//attack
2008-08-09 02:02:32 +03:00
BattleAttack bat ;
2008-09-30 17:50:11 +03:00
prepareAttack ( bat , curStack , stackAtEnd ) ;
2008-08-09 02:02:32 +03:00
sendAndApply ( & bat ) ;
2009-02-03 07:28:05 +02:00
2008-09-12 11:51:46 +03:00
//counterattack
if ( ! vstd : : contains ( curStack - > abilities , NO_ENEMY_RETALIATION )
2008-09-14 10:11:07 +03:00
& & stackAtEnd - > alive ( )
2009-01-29 20:07:31 +02:00
& & stackAtEnd - > counterAttacks
& & ! vstd : : contains ( stackAtEnd - > abilities , SIEGE_WEAPON ) ) //TODO: support for multiple retaliatons per turn
2008-09-12 11:51:46 +03:00
{
2008-09-30 17:50:11 +03:00
prepareAttack ( bat , stackAtEnd , curStack ) ;
2008-09-12 11:51:46 +03:00
bat . flags | = 2 ;
sendAndApply ( & bat ) ;
}
2008-09-14 10:11:07 +03:00
2009-02-03 07:28:05 +02:00
//second attack
2008-09-14 10:11:07 +03:00
if ( vstd : : contains ( curStack - > abilities , TWICE_ATTACK )
2008-09-29 00:01:49 +03:00
& & curStack - > alive ( )
& & stackAtEnd - > alive ( ) )
2008-09-14 10:11:07 +03:00
{
bat . flags = 0 ;
2008-09-30 17:50:11 +03:00
prepareAttack ( bat , curStack , stackAtEnd ) ;
2008-09-14 10:11:07 +03:00
sendAndApply ( & bat ) ;
}
2008-09-29 00:01:49 +03:00
sendDataToClients ( ui16 ( 3008 ) ) ; //end movement and attack
2008-08-04 18:56:36 +03:00
break ;
}
case 7 : //shoot
{
2008-08-09 02:02:32 +03:00
CStack * curStack = gs - > curB - > getStack ( ba . stackNumber ) ,
* destStack = gs - > curB - > getStackT ( ba . destinationTile ) ;
2008-11-01 00:41:22 +02:00
if ( ! curStack //our stack exists
| | ! destStack //there is a stack at destination tile
| | ! curStack - > shots //stack has shots
| | gs - > curB - > isStackBlocked ( curStack - > ID ) //we are not blocked
| | ! vstd : : contains ( curStack - > abilities , SHOOTER ) //our stack is shooting unit
)
break ;
2008-11-17 20:47:43 +02:00
for ( int g = 0 ; g < curStack - > effects . size ( ) ; + + g )
{
if ( 61 = = curStack - > effects [ g ] . id ) //forgetfulness
break ;
}
2008-11-01 00:41:22 +02:00
sendAndApply ( & StartAction ( ba ) ) ; //start shooting
2008-08-09 02:02:32 +03:00
BattleAttack bat ;
2008-09-30 17:50:11 +03:00
prepareAttack ( bat , curStack , destStack ) ;
2008-08-09 02:02:32 +03:00
bat . flags | = 1 ;
2008-11-01 00:41:22 +02:00
sendAndApply ( & bat ) ;
2008-08-09 02:02:32 +03:00
2008-11-01 00:41:22 +02:00
if ( vstd : : contains ( curStack - > abilities , TWICE_ATTACK ) //if unit shots twice let's make another shot
& & curStack - > alive ( )
& & destStack - > alive ( )
& & curStack - > shots
)
2008-09-14 10:11:07 +03:00
{
2008-09-30 17:50:11 +03:00
prepareAttack ( bat , curStack , destStack ) ;
2008-09-14 10:11:07 +03:00
sendAndApply ( & bat ) ;
}
2008-09-29 00:01:49 +03:00
sendDataToClients ( ui16 ( 3008 ) ) ; //end shooting
2008-08-04 18:56:36 +03:00
break ;
}
}
battleMadeAction . setn ( true ) ;
2008-09-29 00:01:49 +03:00
break ;
}
case 3003 : //custom action (probably spell)
{
BattleAction ba ;
c > > ba ;
switch ( ba . actionType )
{
case 1 : //hero casts spell
{
2008-09-29 00:24:22 +03:00
CGHeroInstance * h = ( ba . side ) ? gs - > getHero ( gs - > curB - > hero2 ) : gs - > getHero ( gs - > curB - > hero1 ) ;
2008-10-18 14:41:24 +03:00
if ( ! h )
{
tlog2 < < " Wrong caster! \n " ;
goto customactionend ;
}
if ( ba . additionalInfo > = VLC - > spellh - > spells . size ( ) )
{
tlog2 < < " Wrong spell id ( " < < ba . additionalInfo < < " )! \n " ;
goto customactionend ;
}
2008-09-29 00:01:49 +03:00
CSpell * s = & VLC - > spellh - > spells [ ba . additionalInfo ] ;
2008-12-31 11:33:46 +02:00
ui8 skill = 0 ; //skill level
2008-09-29 00:01:49 +03:00
if ( s - > fire )
2008-09-29 00:24:22 +03:00
skill = std : : max ( skill , h - > getSecSkillLevel ( 14 ) ) ;
2008-09-29 00:01:49 +03:00
if ( s - > air )
2008-09-29 00:24:22 +03:00
skill = std : : max ( skill , h - > getSecSkillLevel ( 15 ) ) ;
2008-09-29 00:01:49 +03:00
if ( s - > water )
2008-09-29 00:24:22 +03:00
skill = std : : max ( skill , h - > getSecSkillLevel ( 16 ) ) ;
2008-09-29 00:01:49 +03:00
if ( s - > earth )
2008-09-29 00:24:22 +03:00
skill = std : : max ( skill , h - > getSecSkillLevel ( 17 ) ) ;
2008-09-29 00:01:49 +03:00
2008-10-18 14:41:24 +03:00
//TODO: skill level may be different on special terrain
if ( // !vstd::contains(h->spells,ba.additionalInfo) //hero doesn't know this spell
/*||*/ ( h - > mana < s - > costs [ skill ] ) //not enough mana
| | ( ba . additionalInfo < 10 ) //it's adventure spell (not combat)
2008-09-29 00:01:49 +03:00
| | 0 ) //TODO: hero has already casted a spell in this round
{
2008-10-18 14:41:24 +03:00
tlog2 < < " Spell cannot be casted! \n " ;
2008-09-29 00:01:49 +03:00
goto customactionend ;
}
sendAndApply ( & StartAction ( ba ) ) ; //start spell casting
2008-10-18 14:41:24 +03:00
//TODO: check resistances
SpellCasted sc ;
sc . side = ba . side ;
sc . id = ba . additionalInfo ;
sc . skill = skill ;
sc . tile = ba . destinationTile ;
sendAndApply ( & sc ) ;
switch ( ba . additionalInfo ) //spell id
{
2008-11-12 20:59:33 +02:00
case 15 : //magic arrow
2008-10-18 14:41:24 +03:00
{
CStack * attacked = gs - > curB - > getStackT ( ba . destinationTile ) ;
if ( ! attacked ) break ;
BattleStackAttacked bsa ;
bsa . flags | = 2 ;
bsa . effect = 64 ;
2008-11-09 00:29:19 +02:00
bsa . damageAmount = h - > getPrimSkillLevel ( 2 ) * 10 + s - > powers [ getSchoolLevel ( h , s ) ] ;
2008-10-18 14:41:24 +03:00
bsa . stackAttacked = attacked - > ID ;
prepareAttacked ( bsa , attacked ) ;
sendAndApply ( & bsa ) ;
break ;
}
2008-11-12 20:59:33 +02:00
case 16 : //ice bolt
2008-11-10 21:06:04 +02:00
{
CStack * attacked = gs - > curB - > getStackT ( ba . destinationTile ) ;
if ( ! attacked ) break ;
BattleStackAttacked bsa ;
bsa . flags | = 2 ;
bsa . effect = 46 ;
bsa . damageAmount = h - > getPrimSkillLevel ( 2 ) * 20 + s - > powers [ getSchoolLevel ( h , s ) ] ;
bsa . stackAttacked = attacked - > ID ;
prepareAttacked ( bsa , attacked ) ;
sendAndApply ( & bsa ) ;
break ;
}
2008-11-12 20:59:33 +02:00
case 17 : //lightning bolt
2008-11-10 21:06:04 +02:00
{
CStack * attacked = gs - > curB - > getStackT ( ba . destinationTile ) ;
if ( ! attacked ) break ;
BattleStackAttacked bsa ;
bsa . flags | = 2 ;
bsa . effect = 38 ;
bsa . damageAmount = h - > getPrimSkillLevel ( 2 ) * 25 + s - > powers [ getSchoolLevel ( h , s ) ] ;
bsa . stackAttacked = attacked - > ID ;
prepareAttacked ( bsa , attacked ) ;
sendAndApply ( & bsa ) ;
break ;
}
2008-11-12 20:59:33 +02:00
case 18 : //implosion
{
CStack * attacked = gs - > curB - > getStackT ( ba . destinationTile ) ;
if ( ! attacked ) break ;
BattleStackAttacked bsa ;
bsa . flags | = 2 ;
bsa . effect = 10 ;
bsa . damageAmount = h - > getPrimSkillLevel ( 2 ) * 75 + s - > powers [ getSchoolLevel ( h , s ) ] ;
bsa . stackAttacked = attacked - > ID ;
prepareAttacked ( bsa , attacked ) ;
sendAndApply ( & bsa ) ;
break ;
}
2008-12-06 18:45:54 +02:00
case 27 : //shield
{
SetStackEffect sse ;
2009-01-15 19:01:08 +02:00
if ( getSchoolLevel ( h , s ) < 3 ) //not expert
{
sse . stack = gs - > curB - > getStackT ( ba . destinationTile ) - > ID ;
sse . effect . id = 27 ;
sse . effect . level = getSchoolLevel ( h , s ) ;
sse . effect . turnsRemain = h - > getPrimSkillLevel ( 2 ) ;
sendAndApply ( & sse ) ;
}
else
{
for ( int it = 0 ; it < gs - > curB - > stacks . size ( ) ; + + it )
{
//if it's non negative spell and our unit or non positive spell and hostile unit
if ( ( VLC - > spellh - > spells [ ba . additionalInfo ] . positiveness > = 0 & & gs - > curB - > stacks [ it ] - > owner = = h - > tempOwner )
| | ( VLC - > spellh - > spells [ ba . additionalInfo ] . positiveness < = 0 & & gs - > curB - > stacks [ it ] - > owner ! = h - > tempOwner )
)
{
sse . stack = gs - > curB - > stacks [ it ] - > ID ;
sse . effect . id = 27 ;
sse . effect . level = getSchoolLevel ( h , s ) ;
sse . effect . turnsRemain = h - > getPrimSkillLevel ( 2 ) ;
sendAndApply ( & sse ) ;
}
}
}
2008-12-06 18:45:54 +02:00
break ;
}
case 28 : //air shield
{
SetStackEffect sse ;
2009-01-15 19:01:08 +02:00
if ( getSchoolLevel ( h , s ) < 3 ) //not expert
{
sse . stack = gs - > curB - > getStackT ( ba . destinationTile ) - > ID ;
sse . effect . id = 28 ;
sse . effect . level = getSchoolLevel ( h , s ) ;
sse . effect . turnsRemain = h - > getPrimSkillLevel ( 2 ) ;
sendAndApply ( & sse ) ;
}
else
{
for ( int it = 0 ; it < gs - > curB - > stacks . size ( ) ; + + it )
{
//if it's non negative spell and our unit or non positive spell and hostile unit
if ( ( VLC - > spellh - > spells [ ba . additionalInfo ] . positiveness > = 0 & & gs - > curB - > stacks [ it ] - > owner = = h - > tempOwner )
| | ( VLC - > spellh - > spells [ ba . additionalInfo ] . positiveness < = 0 & & gs - > curB - > stacks [ it ] - > owner ! = h - > tempOwner )
)
{
sse . stack = gs - > curB - > stacks [ it ] - > ID ;
sse . effect . id = 28 ;
sse . effect . level = getSchoolLevel ( h , s ) ;
sse . effect . turnsRemain = h - > getPrimSkillLevel ( 2 ) ;
sendAndApply ( & sse ) ;
}
}
}
2008-12-06 18:45:54 +02:00
break ;
}
case 41 : //bless
{
SetStackEffect sse ;
2009-01-15 19:01:08 +02:00
if ( getSchoolLevel ( h , s ) < 3 ) //not expert
{
sse . stack = gs - > curB - > getStackT ( ba . destinationTile ) - > ID ;
sse . effect . id = 41 ;
sse . effect . level = getSchoolLevel ( h , s ) ;
sse . effect . turnsRemain = h - > getPrimSkillLevel ( 2 ) ;
sendAndApply ( & sse ) ;
}
else
{
for ( int it = 0 ; it < gs - > curB - > stacks . size ( ) ; + + it )
{
//if it's non negative spell and our unit or non positive spell and hostile unit
if ( ( VLC - > spellh - > spells [ ba . additionalInfo ] . positiveness > = 0 & & gs - > curB - > stacks [ it ] - > owner = = h - > tempOwner )
| | ( VLC - > spellh - > spells [ ba . additionalInfo ] . positiveness < = 0 & & gs - > curB - > stacks [ it ] - > owner ! = h - > tempOwner )
)
{
sse . stack = gs - > curB - > stacks [ it ] - > ID ;
sse . effect . id = 41 ;
sse . effect . level = getSchoolLevel ( h , s ) ;
sse . effect . turnsRemain = h - > getPrimSkillLevel ( 2 ) ;
sendAndApply ( & sse ) ;
}
}
}
2008-12-06 18:45:54 +02:00
break ;
}
case 42 : //curse
{
SetStackEffect sse ;
2009-01-15 19:01:08 +02:00
if ( getSchoolLevel ( h , s ) < 3 ) //not expert
{
sse . stack = gs - > curB - > getStackT ( ba . destinationTile ) - > ID ;
sse . effect . id = 42 ;
sse . effect . level = getSchoolLevel ( h , s ) ;
sse . effect . turnsRemain = h - > getPrimSkillLevel ( 2 ) ;
sendAndApply ( & sse ) ;
}
else
{
for ( int it = 0 ; it < gs - > curB - > stacks . size ( ) ; + + it )
{
//if it's non negative spell and our unit or non positive spell and hostile unit
if ( ( VLC - > spellh - > spells [ ba . additionalInfo ] . positiveness > = 0 & & gs - > curB - > stacks [ it ] - > owner = = h - > tempOwner )
| | ( VLC - > spellh - > spells [ ba . additionalInfo ] . positiveness < = 0 & & gs - > curB - > stacks [ it ] - > owner ! = h - > tempOwner )
)
{
sse . stack = gs - > curB - > stacks [ it ] - > ID ;
sse . effect . id = 42 ;
sse . effect . level = getSchoolLevel ( h , s ) ;
sse . effect . turnsRemain = h - > getPrimSkillLevel ( 2 ) ;
sendAndApply ( & sse ) ;
}
}
}
2008-12-06 18:45:54 +02:00
break ;
}
case 43 : //bloodlust
{
SetStackEffect sse ;
2009-01-15 19:01:08 +02:00
if ( getSchoolLevel ( h , s ) < 3 ) //not expert
{
sse . stack = gs - > curB - > getStackT ( ba . destinationTile ) - > ID ;
sse . effect . id = 43 ;
sse . effect . level = getSchoolLevel ( h , s ) ;
sse . effect . turnsRemain = h - > getPrimSkillLevel ( 2 ) ;
sendAndApply ( & sse ) ;
}
else
{
for ( int it = 0 ; it < gs - > curB - > stacks . size ( ) ; + + it )
{
//if it's non negative spell and our unit or non positive spell and hostile unit
if ( ( VLC - > spellh - > spells [ ba . additionalInfo ] . positiveness > = 0 & & gs - > curB - > stacks [ it ] - > owner = = h - > tempOwner )
| | ( VLC - > spellh - > spells [ ba . additionalInfo ] . positiveness < = 0 & & gs - > curB - > stacks [ it ] - > owner ! = h - > tempOwner )
)
{
sse . stack = gs - > curB - > stacks [ it ] - > ID ;
sse . effect . id = 43 ;
sse . effect . level = getSchoolLevel ( h , s ) ;
sse . effect . turnsRemain = h - > getPrimSkillLevel ( 2 ) ;
sendAndApply ( & sse ) ;
}
}
}
2008-12-06 18:45:54 +02:00
break ;
}
case 45 : //weakness
{
SetStackEffect sse ;
2009-01-15 19:01:08 +02:00
if ( getSchoolLevel ( h , s ) < 3 ) //not expert
{
sse . stack = gs - > curB - > getStackT ( ba . destinationTile ) - > ID ;
sse . effect . id = 45 ;
sse . effect . level = getSchoolLevel ( h , s ) ;
sse . effect . turnsRemain = h - > getPrimSkillLevel ( 2 ) ;
sendAndApply ( & sse ) ;
}
else
{
for ( int it = 0 ; it < gs - > curB - > stacks . size ( ) ; + + it )
{
//if it's non negative spell and our unit or non positive spell and hostile unit
if ( ( VLC - > spellh - > spells [ ba . additionalInfo ] . positiveness > = 0 & & gs - > curB - > stacks [ it ] - > owner = = h - > tempOwner )
| | ( VLC - > spellh - > spells [ ba . additionalInfo ] . positiveness < = 0 & & gs - > curB - > stacks [ it ] - > owner ! = h - > tempOwner )
)
{
sse . stack = gs - > curB - > stacks [ it ] - > ID ;
sse . effect . id = 45 ;
sse . effect . level = getSchoolLevel ( h , s ) ;
sse . effect . turnsRemain = h - > getPrimSkillLevel ( 2 ) ;
sendAndApply ( & sse ) ;
}
}
}
2008-12-06 18:45:54 +02:00
break ;
}
case 46 : //stone skin
{
SetStackEffect sse ;
2009-01-15 19:01:08 +02:00
if ( getSchoolLevel ( h , s ) < 3 ) //not expert
{
sse . stack = gs - > curB - > getStackT ( ba . destinationTile ) - > ID ;
sse . effect . id = 46 ;
sse . effect . level = getSchoolLevel ( h , s ) ;
sse . effect . turnsRemain = h - > getPrimSkillLevel ( 2 ) ;
sendAndApply ( & sse ) ;
}
else
{
for ( int it = 0 ; it < gs - > curB - > stacks . size ( ) ; + + it )
{
//if it's non negative spell and our unit or non positive spell and hostile unit
if ( ( VLC - > spellh - > spells [ ba . additionalInfo ] . positiveness > = 0 & & gs - > curB - > stacks [ it ] - > owner = = h - > tempOwner )
| | ( VLC - > spellh - > spells [ ba . additionalInfo ] . positiveness < = 0 & & gs - > curB - > stacks [ it ] - > owner ! = h - > tempOwner )
)
{
sse . stack = gs - > curB - > stacks [ it ] - > ID ;
sse . effect . id = 46 ;
sse . effect . level = getSchoolLevel ( h , s ) ;
sse . effect . turnsRemain = h - > getPrimSkillLevel ( 2 ) ;
sendAndApply ( & sse ) ;
}
}
}
2008-12-06 18:45:54 +02:00
break ;
}
case 48 : //prayer
{
SetStackEffect sse ;
2009-01-15 19:01:08 +02:00
if ( getSchoolLevel ( h , s ) < 3 ) //not expert
{
sse . stack = gs - > curB - > getStackT ( ba . destinationTile ) - > ID ;
sse . effect . id = 48 ;
sse . effect . level = getSchoolLevel ( h , s ) ;
sse . effect . turnsRemain = h - > getPrimSkillLevel ( 2 ) ;
sendAndApply ( & sse ) ;
}
else
{
for ( int it = 0 ; it < gs - > curB - > stacks . size ( ) ; + + it )
{
//if it's non negative spell and our unit or non positive spell and hostile unit
if ( ( VLC - > spellh - > spells [ ba . additionalInfo ] . positiveness > = 0 & & gs - > curB - > stacks [ it ] - > owner = = h - > tempOwner )
| | ( VLC - > spellh - > spells [ ba . additionalInfo ] . positiveness < = 0 & & gs - > curB - > stacks [ it ] - > owner ! = h - > tempOwner )
)
{
sse . stack = gs - > curB - > stacks [ it ] - > ID ;
sse . effect . id = 48 ;
sse . effect . level = getSchoolLevel ( h , s ) ;
sse . effect . turnsRemain = h - > getPrimSkillLevel ( 2 ) ;
sendAndApply ( & sse ) ;
}
}
}
2008-12-06 18:45:54 +02:00
break ;
}
2008-10-18 14:41:24 +03:00
case 53 : //haste
{
2008-11-09 00:29:19 +02:00
SetStackEffect sse ;
2009-01-15 19:01:08 +02:00
if ( getSchoolLevel ( h , s ) < 3 ) //not expert
{
sse . stack = gs - > curB - > getStackT ( ba . destinationTile ) - > ID ;
sse . effect . id = 53 ;
sse . effect . level = getSchoolLevel ( h , s ) ;
sse . effect . turnsRemain = h - > getPrimSkillLevel ( 2 ) ;
sendAndApply ( & sse ) ;
}
else
{
for ( int it = 0 ; it < gs - > curB - > stacks . size ( ) ; + + it )
{
//if it's non negative spell and our unit or non positive spell and hostile unit
if ( ( VLC - > spellh - > spells [ ba . additionalInfo ] . positiveness > = 0 & & gs - > curB - > stacks [ it ] - > owner = = h - > tempOwner )
| | ( VLC - > spellh - > spells [ ba . additionalInfo ] . positiveness < = 0 & & gs - > curB - > stacks [ it ] - > owner ! = h - > tempOwner )
)
{
sse . stack = gs - > curB - > stacks [ it ] - > ID ;
sse . effect . id = 53 ;
sse . effect . level = getSchoolLevel ( h , s ) ;
sse . effect . turnsRemain = h - > getPrimSkillLevel ( 2 ) ;
sendAndApply ( & sse ) ;
}
}
}
2008-10-18 14:41:24 +03:00
break ;
}
2008-11-11 17:17:58 +02:00
case 54 : //slow
{
SetStackEffect sse ;
2009-01-15 19:01:08 +02:00
if ( getSchoolLevel ( h , s ) < 3 ) //not expert
{
sse . stack = gs - > curB - > getStackT ( ba . destinationTile ) - > ID ;
sse . effect . id = 54 ;
sse . effect . level = getSchoolLevel ( h , s ) ;
sse . effect . turnsRemain = h - > getPrimSkillLevel ( 2 ) ;
sendAndApply ( & sse ) ;
}
else
{
for ( int it = 0 ; it < gs - > curB - > stacks . size ( ) ; + + it )
{
//if it's non negative spell and our unit or non positive spell and hostile unit
if ( ( VLC - > spellh - > spells [ ba . additionalInfo ] . positiveness > = 0 & & gs - > curB - > stacks [ it ] - > owner = = h - > tempOwner )
| | ( VLC - > spellh - > spells [ ba . additionalInfo ] . positiveness < = 0 & & gs - > curB - > stacks [ it ] - > owner ! = h - > tempOwner )
)
{
sse . stack = gs - > curB - > stacks [ it ] - > ID ;
sse . effect . id = 54 ;
sse . effect . level = getSchoolLevel ( h , s ) ;
sse . effect . turnsRemain = h - > getPrimSkillLevel ( 2 ) ;
sendAndApply ( & sse ) ;
}
}
}
2008-11-11 17:17:58 +02:00
break ;
}
2008-12-20 19:08:51 +02:00
case 56 : //frenzy
{
SetStackEffect sse ;
2009-01-15 19:01:08 +02:00
if ( getSchoolLevel ( h , s ) < 3 ) //not expert
{
sse . stack = gs - > curB - > getStackT ( ba . destinationTile ) - > ID ;
sse . effect . id = 56 ;
sse . effect . level = getSchoolLevel ( h , s ) ;
sse . effect . turnsRemain = 1 ; //! - different duration
sendAndApply ( & sse ) ;
}
else
{
for ( int it = 0 ; it < gs - > curB - > stacks . size ( ) ; + + it )
{
//if it's non negative spell and our unit or non positive spell and hostile unit
if ( ( VLC - > spellh - > spells [ ba . additionalInfo ] . positiveness > = 0 & & gs - > curB - > stacks [ it ] - > owner = = h - > tempOwner )
| | ( VLC - > spellh - > spells [ ba . additionalInfo ] . positiveness < = 0 & & gs - > curB - > stacks [ it ] - > owner ! = h - > tempOwner )
)
{
sse . stack = gs - > curB - > stacks [ it ] - > ID ;
sse . effect . id = 56 ;
sse . effect . level = getSchoolLevel ( h , s ) ;
sse . effect . turnsRemain = h - > getPrimSkillLevel ( 2 ) ;
sendAndApply ( & sse ) ;
}
}
}
2008-12-20 19:08:51 +02:00
break ;
}
2008-11-17 20:47:43 +02:00
case 61 : //forgetfulness
{
SetStackEffect sse ;
2009-01-15 19:01:08 +02:00
if ( getSchoolLevel ( h , s ) < 3 ) //not expert
{
sse . stack = gs - > curB - > getStackT ( ba . destinationTile ) - > ID ;
sse . effect . id = 61 ;
sse . effect . level = getSchoolLevel ( h , s ) ;
sse . effect . turnsRemain = h - > getPrimSkillLevel ( 2 ) ;
sendAndApply ( & sse ) ;
}
else
{
for ( int it = 0 ; it < gs - > curB - > stacks . size ( ) ; + + it )
{
//if it's non negative spell and our unit or non positive spell and hostile unit
if ( ( VLC - > spellh - > spells [ ba . additionalInfo ] . positiveness > = 0 & & gs - > curB - > stacks [ it ] - > owner = = h - > tempOwner )
| | ( VLC - > spellh - > spells [ ba . additionalInfo ] . positiveness < = 0 & & gs - > curB - > stacks [ it ] - > owner ! = h - > tempOwner )
)
{
sse . stack = gs - > curB - > stacks [ it ] - > ID ;
sse . effect . id = 61 ;
sse . effect . level = getSchoolLevel ( h , s ) ;
sse . effect . turnsRemain = h - > getPrimSkillLevel ( 2 ) ;
sendAndApply ( & sse ) ;
}
}
}
2008-11-17 20:47:43 +02:00
break ;
}
2008-10-18 14:41:24 +03:00
}
//TODO: spells to support possibly soon (list by Zamolxis):
/*- Magic Arrow
- Haste
- Bless
- Bloodlust
- Curse
- Dispel
- Shield
- Slow
- Stone Skin
- Lightning Bolt
- Ice Bolt
- Precision
- Blind
- Fire Wall
- Weakness
- Death Ripple */
2008-09-29 00:01:49 +03:00
sendDataToClients ( ui16 ( 3008 ) ) ; //end casting
break ;
}
}
customactionend :
2008-07-31 16:21:42 +03:00
break ;
}
2008-07-27 20:07:37 +03:00
default :
2008-09-23 13:58:54 +03:00
throw std : : string ( " Not supported client message! " ) ;
2008-07-27 20:07:37 +03:00
}
2008-07-25 20:28:28 +03:00
}
}
2009-01-25 18:19:34 +02:00
HANDLE_EXCEPTION ( end2 = true ) ;
2008-08-16 11:47:41 +03:00
handleConEnd :
2008-09-23 13:58:54 +03:00
tlog1 < < " Ended handling connection \n " ;
2008-07-25 20:28:28 +03:00
}
2008-08-09 02:02:32 +03:00
void CGameHandler : : moveStack ( int stack , int dest )
{
CStack * curStack = gs - > curB - > getStack ( stack ) ,
* stackAtEnd = gs - > curB - > getStackT ( dest ) ;
//initing necessary tables
2008-11-10 21:06:04 +02:00
bool accessibility [ BFIELD_SIZE ] ;
2008-08-09 02:02:32 +03:00
if ( curStack - > creature - > isDoubleWide ( ) )
gs - > curB - > getAccessibilityMapForTwoHex ( accessibility , curStack - > attackerOwned , curStack - > ID ) ;
else
gs - > curB - > getAccessibilityMap ( accessibility , curStack - > ID ) ;
2009-02-05 16:44:27 +02:00
//shifting destination (if we have double wide stack and we can occupy dest but not be exactly there)
if ( ! stackAtEnd & & curStack - > creature - > isDoubleWide ( ) & & ! accessibility [ dest ] )
{
if ( curStack - > attackerOwned )
{
if ( accessibility [ dest + 1 ] )
dest + = 1 ;
}
else
{
if ( accessibility [ dest - 1 ] )
dest - = 1 ;
}
}
2008-09-12 11:51:46 +03:00
if ( ( stackAtEnd & & stackAtEnd ! = curStack & & stackAtEnd - > alive ( ) ) | | ! accessibility [ dest ] )
2008-08-09 02:02:32 +03:00
return ;
//if(dists[dest] > curStack->creature->speed && !(stackAtEnd && dists[dest] == curStack->creature->speed+1)) //we can attack a stack if we can go to adjacent hex
// return false;
std : : vector < int > path = gs - > curB - > getPath ( curStack - > position , dest , accessibility ) ;
2008-11-10 21:06:04 +02:00
int tilesToMove = std : : max ( ( int ) ( path . size ( ) - curStack - > speed ( ) ) , 0 ) ;
2008-08-09 02:02:32 +03:00
for ( int v = path . size ( ) - 1 ; v > = tilesToMove ; - - v )
{
//inform clients about move
BattleStackMoved sm ;
sm . stack = curStack - > ID ;
sm . tile = path [ v ] ;
sendAndApply ( & sm ) ;
}
}
2008-07-01 11:01:02 +03:00
CGameHandler : : CGameHandler ( void )
{
2008-07-25 20:28:28 +03:00
gs = NULL ;
2009-01-12 22:05:56 +02:00
IObjectInterface : : cb = this ;
2008-07-01 11:01:02 +03:00
}
CGameHandler : : ~ CGameHandler ( void )
{
2008-07-25 20:28:28 +03:00
delete gs ;
}
void CGameHandler : : init ( StartInfo * si , int Seed )
{
Mapa * map = new Mapa ( si - > mapname ) ;
2008-09-19 15:09:15 +03:00
tlog0 < < " Map loaded! " < < std : : endl ;
2008-07-25 20:28:28 +03:00
gs = new CGameState ( ) ;
2008-09-19 15:09:15 +03:00
tlog0 < < " Gamestate created! " < < std : : endl ;
2008-07-30 20:51:19 +03:00
gs - > init ( si , map , Seed ) ;
2008-09-19 15:09:15 +03:00
tlog0 < < " Gamestate initialized! " < < std : : endl ;
2008-12-22 19:48:41 +02:00
2008-07-30 20:51:19 +03:00
/****************************LUA OBJECT SCRIPTS************************************************/
//std::vector<std::string> * lf = CLuaHandler::searchForScripts("scripts/lua/objects"); //files
//for (int i=0; i<lf->size(); i++)
//{
// try
// {
// std::vector<std::string> * temp = CLuaHandler::functionList((*lf)[i]);
// CLuaObjectScript * objs = new CLuaObjectScript((*lf)[i]);
// CLuaCallback::registerFuncs(objs->is);
// //objs
// for (int j=0; j<temp->size(); j++)
// {
// int obid ; //obj ID
// int dspos = (*temp)[j].find_first_of('_');
// obid = atoi((*temp)[j].substr(dspos+1,(*temp)[j].size()-dspos-1).c_str());
// std::string fname = (*temp)[j].substr(0,dspos);
// if (skrypty->find(obid)==skrypty->end())
// skrypty->insert(std::pair<int, std::map<std::string, CObjectScript*> >(obid,std::map<std::string,CObjectScript*>()));
// (*skrypty)[obid].insert(std::pair<std::string, CObjectScript*>(fname,objs));
// }
// delete temp;
// }HANDLE_EXCEPTION
//}
//delete lf;
2009-01-11 00:08:18 +02:00
for ( std : : map < ui8 , PlayerState > : : iterator i = gs - > players . begin ( ) ; i ! = gs - > players . end ( ) ; i + + )
states . addPlayer ( i - > first ) ;
2008-07-01 11:01:02 +03:00
}
2008-09-28 16:29:37 +03:00
2008-07-25 20:28:28 +03:00
void CGameHandler : : newTurn ( )
{
2008-10-26 22:58:34 +02:00
tlog5 < < " Turn " < < gs - > day + 1 < < std : : endl ;
2008-07-26 16:57:32 +03:00
NewTurn n ;
n . day = gs - > day + 1 ;
2008-08-10 07:46:16 +03:00
n . resetBuilded = true ;
2008-07-26 16:57:32 +03:00
2008-07-25 20:28:28 +03:00
for ( std : : map < ui8 , PlayerState > : : iterator i = gs - > players . begin ( ) ; i ! = gs - > players . end ( ) ; i + + )
{
2008-11-01 00:41:22 +02:00
if ( i - > first = = 255 ) continue ;
2008-10-26 22:58:34 +02:00
if ( gs - > getDate ( 1 ) = = 7 ) //first day of week - new heroes in tavern
{
SetAvailableHeroes sah ;
sah . player = i - > first ;
2008-11-01 00:41:22 +02:00
//TODO: - will fail when there are not enough available heroes
sah . hid1 = gs - > hpool . pickHeroFor ( true , i - > first , & VLC - > townh - > towns [ gs - > scenarioOps - > getIthPlayersSettings ( i - > first ) . castle ] ) - > subID ;
sah . hid2 = gs - > hpool . pickHeroFor ( false , i - > first , & VLC - > townh - > towns [ gs - > scenarioOps - > getIthPlayersSettings ( i - > first ) . castle ] , sah . hid1 ) - > subID ;
2008-10-26 22:58:34 +02:00
sendAndApply ( & sah ) ;
}
2008-07-26 16:57:32 +03:00
if ( i - > first > = PLAYER_LIMIT ) continue ;
2008-08-10 07:46:16 +03:00
SetResources r ;
2008-07-26 16:57:32 +03:00
r . player = i - > first ;
for ( int j = 0 ; j < RESOURCE_QUANTITY ; j + + )
2008-08-10 07:46:16 +03:00
r . res [ j ] = i - > second . resources [ j ] ;
2008-07-26 16:57:32 +03:00
2008-10-18 14:41:24 +03:00
BOOST_FOREACH ( CGHeroInstance * h , ( * i ) . second . heroes )
2008-07-25 20:28:28 +03:00
{
2008-10-18 14:41:24 +03:00
NewTurn : : Hero hth ;
hth . id = h - > id ;
2008-10-26 22:58:34 +02:00
hth . move = h - > maxMovePoints ( true ) ; //TODO: check if hero is really on the land
2008-10-19 02:20:48 +03:00
hth . mana = std : : max ( h - > mana , std : : min ( h - > mana + 1 + h - > getSecSkillLevel ( 8 ) , h - > manaLimit ( ) ) ) ; //hero regains 1 mana point + mysticism lvel
2008-10-18 14:41:24 +03:00
n . heroes . insert ( hth ) ;
2008-11-01 00:41:22 +02:00
switch ( h - > getSecSkillLevel ( 13 ) ) //handle estates - give gold
2008-09-28 16:29:37 +03:00
{
case 1 : //basic
r . res [ 6 ] + = 125 ;
break ;
case 2 : //advanced
r . res [ 6 ] + = 250 ;
break ;
case 3 : //expert
r . res [ 6 ] + = 500 ;
break ;
}
2008-07-25 20:28:28 +03:00
}
2008-08-10 07:46:16 +03:00
for ( std : : vector < CGTownInstance * > : : iterator j = i - > second . towns . begin ( ) ; j ! = i - > second . towns . end ( ) ; j + + ) //handle towns
2008-07-25 20:28:28 +03:00
{
2008-09-12 11:51:46 +03:00
if ( vstd : : contains ( ( * * j ) . builtBuildings , 15 ) ) //there is resource silo
{
if ( ( * * j ) . town - > primaryRes = = 127 ) //we'll give wood and ore
{
r . res [ 0 ] + = 1 ;
r . res [ 2 ] + = 1 ;
}
else
{
r . res [ ( * * j ) . town - > primaryRes ] + = 1 ;
}
}
2008-08-10 07:46:16 +03:00
if ( gs - > getDate ( 1 ) = = 7 ) //first day of week
{
SetAvailableCreatures sac ;
sac . tid = ( * * j ) . id ;
sac . creatures = ( * * j ) . strInfo . creatures ;
for ( int k = 0 ; k < CREATURES_PER_TOWN ; k + + ) //creature growths
{
if ( ( * * j ) . creatureDwelling ( k ) ) //there is dwelling (k-level)
sac . creatures [ k ] + = ( * * j ) . creatureGrowth ( k ) ;
}
n . cres . push_back ( sac ) ;
}
2008-07-27 20:07:37 +03:00
if ( ( gs - > day ) & & i - > first < PLAYER_LIMIT ) //not the first day and town not neutral
2008-08-10 07:46:16 +03:00
r . res [ 6 ] + = ( * * j ) . dailyIncome ( ) ;
2008-07-25 20:28:28 +03:00
}
2008-08-10 07:46:16 +03:00
n . res . push_back ( r ) ;
2008-07-25 20:28:28 +03:00
}
2008-07-30 20:51:19 +03:00
sendAndApply ( & n ) ;
2008-10-26 22:58:34 +02:00
tlog5 < < " Info about turn " < < n . day < < " has been sent! " < < std : : endl ;
2008-12-22 19:48:41 +02:00
for ( size_t i = 0 ; i < gs - > map - > objects . size ( ) ; i + + )
2008-12-27 03:01:59 +02:00
if ( gs - > map - > objects [ i ] )
gs - > map - > objects [ i ] - > newTurn ( ) ;
2008-07-25 20:28:28 +03:00
}
2009-01-11 00:08:18 +02:00
void CGameHandler : : run ( bool resume )
2008-07-25 20:28:28 +03:00
{
BOOST_FOREACH ( CConnection * cc , conns )
{ //init conn.
ui8 quantity , pom ;
//ui32 seed;
2009-01-11 00:08:18 +02:00
if ( ! resume )
( * cc ) < < gs - > scenarioOps - > mapname < < gs - > map - > checksum < < gs - > seed ;
2008-10-18 14:41:24 +03:00
( * cc ) > > quantity ; //how many players will be handled at that client
2008-07-25 20:28:28 +03:00
for ( int i = 0 ; i < quantity ; i + + )
{
2008-10-18 14:41:24 +03:00
( * cc ) > > pom ; //read player color
2008-07-25 20:28:28 +03:00
gsm . lock ( ) ;
connections [ pom ] = cc ;
gsm . unlock ( ) ;
}
}
2008-08-15 15:11:42 +03:00
2008-07-25 20:28:28 +03:00
for ( std : : set < CConnection * > : : iterator i = conns . begin ( ) ; i ! = conns . end ( ) ; i + + )
{
std : : set < int > pom ;
for ( std : : map < int , CConnection * > : : iterator j = connections . begin ( ) ; j ! = connections . end ( ) ; j + + )
if ( j - > second = = * i )
pom . insert ( j - > first ) ;
boost : : thread ( boost : : bind ( & CGameHandler : : handleConnection , this , pom , boost : : ref ( * * i ) ) ) ;
}
2008-07-31 00:27:15 +03:00
/****************************SCRIPTS************************************************/
//std::map<int, std::map<std::string, CObjectScript*> > * skrypty = &objscr; //alias for easier access
/****************************C++ OBJECT SCRIPTS************************************************/
2008-12-22 19:48:41 +02:00
//std::map<int,CCPPObjectScript*> scripts;
//CScriptCallback * csc = new CScriptCallback();
//csc->gh = this;
//handleCPPObjS(&scripts,new CVisitableOPH(csc));
//handleCPPObjS(&scripts,new CVisitableOPW(csc));
//handleCPPObjS(&scripts,new CPickable(csc));
//handleCPPObjS(&scripts,new CMines(csc));
//handleCPPObjS(&scripts,new CTownScript(csc));
//handleCPPObjS(&scripts,new CHeroScript(csc));
//handleCPPObjS(&scripts,new CMonsterS(csc));
//handleCPPObjS(&scripts,new CCreatureGen(csc));
//handleCPPObjS(&scripts,new CTeleports(csc));
2008-07-31 00:27:15 +03:00
/****************************INITIALIZING OBJECT SCRIPTS************************************************/
//std::string temps("newObject");
2008-12-22 19:48:41 +02:00
//for (unsigned i=0; i<gs->map->objects.size(); i++)
//{
2008-07-31 00:27:15 +03:00
//c++ scripts
2008-12-22 19:48:41 +02:00
//if (scripts.find(gs->map->objects[i]->ID) != scripts.end())
//{
// gs->map->objects[i]->state = scripts[gs->map->objects[i]->ID];
// gs->map->objects[i]->state->newObject(gs->map->objects[i]->id);
//}
//else
//{
// gs->map->objects[i]->state = NULL;
//}
2008-07-31 00:27:15 +03:00
//// lua scripts
//if(checkFunc(map->objects[i]->ID,temps))
// (*skrypty)[map->objects[i]->ID][temps]->newObject(map->objects[i]);
2008-12-22 19:48:41 +02:00
//}
2008-07-31 00:27:15 +03:00
2008-08-04 12:05:52 +03:00
while ( ! end2 )
2008-07-25 20:28:28 +03:00
{
2009-01-25 18:19:34 +02:00
if ( ! resume )
newTurn ( ) ;
else
resume = false ;
2009-01-11 00:08:18 +02:00
std : : map < ui8 , PlayerState > : : iterator i ;
if ( ! resume )
i = gs - > players . begin ( ) ;
else
i = gs - > players . find ( gs - > currentPlayer ) ;
for ( ; i ! = gs - > players . end ( ) ; i + + )
2008-07-25 20:28:28 +03:00
{
2009-01-11 00:08:18 +02:00
2008-08-01 21:13:33 +03:00
if ( ( i - > second . towns . size ( ) = = 0 & & i - > second . heroes . size ( ) = = 0 ) | | i - > second . color < 0 | | i - > first > = PLAYER_LIMIT ) continue ; //players has not towns/castle - loser
2008-08-13 03:44:31 +03:00
states . setFlag ( i - > first , & PlayerStatus : : makingTurn , true ) ;
2008-07-28 15:44:08 +03:00
gs - > currentPlayer = i - > first ;
2008-07-25 20:28:28 +03:00
* connections [ i - > first ] < < ui16 ( 100 ) < < i - > first ;
2008-08-13 03:44:31 +03:00
2008-07-25 20:28:28 +03:00
//wait till turn is done
2008-08-13 03:44:31 +03:00
boost : : unique_lock < boost : : mutex > lock ( states . mx ) ;
while ( states . players [ i - > first ] . makingTurn & & ! end2 )
2008-07-25 20:28:28 +03:00
{
2008-07-27 20:07:37 +03:00
boost : : posix_time : : time_duration p ;
2008-08-25 13:25:16 +03:00
p = boost : : posix_time : : milliseconds ( 200 ) ;
2008-08-09 02:02:32 +03:00
# ifdef _MSC_VER
2008-08-13 03:44:31 +03:00
states . cv . timed_wait ( lock , p ) ;
2008-08-09 02:02:32 +03:00
# else
2008-08-04 12:05:52 +03:00
boost : : xtime time = { 0 , 0 } ;
2008-08-25 13:25:16 +03:00
time . nsec = static_cast < boost : : xtime : : xtime_nsec_t > ( p . total_nanoseconds ( ) ) ;
2008-08-17 17:09:30 +03:00
states . cv . timed_wait ( lock , time ) ;
2008-08-09 02:02:32 +03:00
# endif
2008-07-25 20:28:28 +03:00
}
}
}
2008-08-04 12:05:52 +03:00
}
2008-08-15 15:11:42 +03:00
2008-09-17 14:55:03 +03:00
namespace CGH
{
using namespace std ;
void readItTo ( ifstream & input , vector < vector < int > > & dest )
{
for ( int j = 0 ; j < 7 ; + + j )
{
std : : vector < int > pom ;
for ( int g = 0 ; g < j + 1 ; + + g )
{
int hlp ; input > > hlp ;
pom . push_back ( hlp ) ;
}
dest . push_back ( pom ) ;
}
}
}
2008-08-15 15:11:42 +03:00
void CGameHandler : : setupBattle ( BattleInfo * curB , int3 tile , CCreatureSet & army1 , CCreatureSet & army2 , CGHeroInstance * hero1 , CGHeroInstance * hero2 )
{
battleResult . set ( NULL ) ;
std : : vector < CStack * > & stacks = ( curB - > stacks ) ;
curB - > tile = tile ;
curB - > siege = 0 ; //TODO: add sieges
curB - > army1 = army1 ;
curB - > army2 = army2 ;
curB - > hero1 = ( hero1 ) ? ( hero1 - > id ) : ( - 1 ) ;
curB - > hero2 = ( hero2 ) ? ( hero2 - > id ) : ( - 1 ) ;
curB - > side1 = ( hero1 ) ? ( hero1 - > tempOwner ) : ( - 1 ) ;
curB - > side2 = ( hero2 ) ? ( hero2 - > tempOwner ) : ( - 1 ) ;
curB - > round = - 2 ;
curB - > activeStack = - 1 ;
for ( std : : map < si32 , std : : pair < ui32 , si32 > > : : iterator i = army1 . slots . begin ( ) ; i ! = army1 . slots . end ( ) ; i + + )
{
2008-09-09 10:05:02 +03:00
stacks . push_back ( new CStack ( & VLC - > creh - > creatures [ i - > second . first ] , i - > second . second , hero1 - > tempOwner , stacks . size ( ) , true , i - > first ) ) ;
2009-02-05 11:49:45 +02:00
//base luck/morale calculations
//TODO: check if terrain is native, add bonuses for neutral stacks, bonuses from town
if ( hero1 )
{
stacks . back ( ) - > morale = hero1 - > getCurrentMorale ( i - > first , false ) ;
stacks . back ( ) - > luck = hero1 - > getCurrentLuck ( i - > first , false ) ;
}
else
{
stacks . back ( ) - > morale = 0 ;
stacks . back ( ) - > luck = 0 ;
}
2008-08-15 15:11:42 +03:00
stacks [ stacks . size ( ) - 1 ] - > ID = stacks . size ( ) - 1 ;
}
//initialization of positions
2008-09-17 14:55:03 +03:00
std : : ifstream positions ;
positions . open ( " config " PATHSEPARATOR " battleStartpos.txt " , std : : ios_base : : in | std : : ios_base : : binary ) ;
if ( ! positions . is_open ( ) )
2008-08-15 15:11:42 +03:00
{
2008-09-19 14:19:14 +03:00
tlog1 < < " Unable to open battleStartpos.txt! " < < std : : endl ;
2008-08-15 15:11:42 +03:00
}
2008-09-17 14:55:03 +03:00
std : : string dump ;
positions > > dump ; positions > > dump ;
std : : vector < std : : vector < int > > attackerLoose , defenderLoose , attackerTight , defenderTight ;
CGH : : readItTo ( positions , attackerLoose ) ;
positions > > dump ;
CGH : : readItTo ( positions , defenderLoose ) ;
positions > > dump ;
positions > > dump ;
CGH : : readItTo ( positions , attackerTight ) ;
positions > > dump ;
CGH : : readItTo ( positions , defenderTight ) ;
positions . close ( ) ;
if ( army1 . formation )
for ( int b = 0 ; b < army1 . slots . size ( ) ; + + b ) //tight
{
stacks [ b ] - > position = attackerTight [ army1 . slots . size ( ) - 1 ] [ b ] ;
}
else
for ( int b = 0 ; b < army1 . slots . size ( ) ; + + b ) //loose
{
stacks [ b ] - > position = attackerLoose [ army1 . slots . size ( ) - 1 ] [ b ] ;
}
2008-08-15 15:11:42 +03:00
for ( std : : map < si32 , std : : pair < ui32 , si32 > > : : iterator i = army2 . slots . begin ( ) ; i ! = army2 . slots . end ( ) ; i + + )
2009-02-05 11:49:45 +02:00
{
2008-09-09 10:05:02 +03:00
stacks . push_back ( new CStack ( & VLC - > creh - > creatures [ i - > second . first ] , i - > second . second , hero2 ? hero2 - > tempOwner : 255 , stacks . size ( ) , false , i - > first ) ) ;
2009-02-05 11:49:45 +02:00
//base luck/morale calculations
//TODO: check if terrain is native, add bonuses for neutral stacks, bonuses from town
if ( hero2 )
{
stacks . back ( ) - > morale = hero2 - > getCurrentMorale ( i - > first , false ) ;
stacks . back ( ) - > luck = hero2 - > getCurrentLuck ( i - > first , false ) ;
}
else
{
stacks . back ( ) - > morale = 0 ;
stacks . back ( ) - > luck = 0 ;
}
}
2008-09-17 14:55:03 +03:00
if ( army2 . formation )
for ( int b = 0 ; b < army2 . slots . size ( ) ; + + b ) //tight
{
stacks [ b + army1 . slots . size ( ) ] - > position = defenderTight [ army2 . slots . size ( ) - 1 ] [ b ] ;
}
else
for ( int b = 0 ; b < army2 . slots . size ( ) ; + + b ) //loose
{
stacks [ b + army1 . slots . size ( ) ] - > position = defenderLoose [ army2 . slots . size ( ) - 1 ] [ b ] ;
}
2008-08-15 15:11:42 +03:00
for ( unsigned g = 0 ; g < stacks . size ( ) ; + + g ) //shifting positions of two-hex creatures
{
if ( ( stacks [ g ] - > position % 17 ) = = 1 & & stacks [ g ] - > creature - > isDoubleWide ( ) )
{
stacks [ g ] - > position + = 1 ;
}
else if ( ( stacks [ g ] - > position % 17 ) = = 15 & & stacks [ g ] - > creature - > isDoubleWide ( ) )
{
stacks [ g ] - > position - = 1 ;
}
}
2008-11-06 19:17:48 +02:00
//adding war machines
if ( hero1 )
{
2009-02-04 05:55:12 +02:00
if ( hero1 - > getArt ( 13 ) ) //ballista
2008-11-06 19:17:48 +02:00
{
stacks . push_back ( new CStack ( & VLC - > creh - > creatures [ 146 ] , 1 , hero1 - > tempOwner , stacks . size ( ) , true , 255 ) ) ;
stacks [ stacks . size ( ) - 1 ] - > position = 52 ;
}
2009-02-04 05:55:12 +02:00
if ( hero1 - > getArt ( 14 ) ) //ammo cart
2008-11-06 19:17:48 +02:00
{
stacks . push_back ( new CStack ( & VLC - > creh - > creatures [ 148 ] , 1 , hero1 - > tempOwner , stacks . size ( ) , true , 255 ) ) ;
stacks [ stacks . size ( ) - 1 ] - > position = 18 ;
}
2009-02-04 05:55:12 +02:00
if ( hero1 - > getArt ( 15 ) ) //first aid tent
2008-11-06 19:17:48 +02:00
{
stacks . push_back ( new CStack ( & VLC - > creh - > creatures [ 147 ] , 1 , hero1 - > tempOwner , stacks . size ( ) , true , 255 ) ) ;
stacks [ stacks . size ( ) - 1 ] - > position = 154 ;
}
}
if ( hero2 )
{
2009-02-05 16:44:27 +02:00
if ( hero2 - > getArt ( 13 ) ) //ballista
2008-11-06 19:17:48 +02:00
{
stacks . push_back ( new CStack ( & VLC - > creh - > creatures [ 146 ] , 1 , hero2 - > tempOwner , stacks . size ( ) , false , 255 ) ) ;
stacks [ stacks . size ( ) - 1 ] - > position = 66 ;
}
2009-02-04 05:55:12 +02:00
if ( hero2 - > getArt ( 14 ) ) //ammo cart
2008-11-06 19:17:48 +02:00
{
stacks . push_back ( new CStack ( & VLC - > creh - > creatures [ 148 ] , 1 , hero2 - > tempOwner , stacks . size ( ) , false , 255 ) ) ;
stacks [ stacks . size ( ) - 1 ] - > position = 32 ;
}
2009-02-04 05:55:12 +02:00
if ( hero2 - > getArt ( 15 ) ) //first aid tent
2008-11-06 19:17:48 +02:00
{
stacks . push_back ( new CStack ( & VLC - > creh - > creatures [ 147 ] , 1 , hero2 - > tempOwner , stacks . size ( ) , false , 255 ) ) ;
stacks [ stacks . size ( ) - 1 ] - > position = 168 ;
}
}
//war machiens added
2008-08-15 15:11:42 +03:00
std : : stable_sort ( stacks . begin ( ) , stacks . end ( ) , cmpst ) ;
//block engaged players
if ( hero1 - > tempOwner < PLAYER_LIMIT )
states . setFlag ( hero1 - > tempOwner , & PlayerStatus : : engagedIntoBattle , true ) ;
if ( hero2 & & hero2 - > tempOwner < PLAYER_LIMIT )
states . setFlag ( hero2 - > tempOwner , & PlayerStatus : : engagedIntoBattle , true ) ;
//send info about battles
BattleStart bs ;
bs . info = curB ;
sendAndApply ( & bs ) ;
2008-08-17 17:09:30 +03:00
}
2008-09-09 10:05:02 +03:00
void CGameHandler : : checkForBattleEnd ( std : : vector < CStack * > & stacks )
{
//checking winning condition
bool hasStack [ 2 ] ; //hasStack[0] - true if attacker has a living stack; defender similarily
hasStack [ 0 ] = hasStack [ 1 ] = false ;
for ( int b = 0 ; b < stacks . size ( ) ; + + b )
{
2008-09-12 11:51:46 +03:00
if ( stacks [ b ] - > alive ( ) )
2008-09-09 10:05:02 +03:00
{
hasStack [ 1 - stacks [ b ] - > attackerOwned ] = true ;
}
}
if ( ! hasStack [ 0 ] | | ! hasStack [ 1 ] ) //somebody has won
{
2008-09-12 11:51:46 +03:00
BattleResult * br = new BattleResult ; //will be deleted at the end of startBattle(...)
2008-09-09 10:05:02 +03:00
br - > result = 0 ;
br - > winner = hasStack [ 1 ] ; //fleeing side loses
gs - > curB - > calculateCasualties ( br - > casualties ) ;
battleResult . set ( br ) ;
}
2008-09-12 11:51:46 +03:00
}
void CGameHandler : : giveSpells ( const CGTownInstance * t , const CGHeroInstance * h )
{
if ( ! vstd : : contains ( h - > artifWorn , 17 ) )
return ; //hero hasn't spellbok
ChangeSpells cs ;
cs . hid = h - > id ;
cs . learn = true ;
for ( int i = 0 ; i < std : : min ( t - > mageGuildLevel ( ) , h - > getSecSkillLevel ( 7 ) + 4 ) ; i + + )
{
2008-09-20 21:30:37 +03:00
for ( int j = 0 ; j < t - > spellsAtLevel ( i + 1 , true ) & & j < t - > spells [ i ] . size ( ) ; j + + )
2008-09-12 11:51:46 +03:00
{
if ( ! vstd : : contains ( h - > spells , t - > spells [ i ] [ j ] ) )
cs . spells . insert ( t - > spells [ i ] [ j ] ) ;
}
}
if ( cs . spells . size ( ) )
sendAndApply ( & cs ) ;
2008-09-18 23:24:53 +03:00
}
2008-12-22 19:48:41 +02:00
void CGameHandler : : setBlockVis ( int objid , bool bv )
{
SetObjectProperty sop ( objid , 2 , bv ) ;
sendAndApply ( & sop ) ;
}
void CGameHandler : : removeObject ( int objid )
{
RemoveObject ro ;
ro . id = objid ;
sendAndApply ( & ro ) ;
}
void CGameHandler : : setAmount ( int objid , ui32 val )
{
SetObjectProperty sop ( objid , 3 , val ) ;
sendAndApply ( & sop ) ;
}
void CGameHandler : : moveHero ( int hid , int3 pos , bool instant )
{
if ( ! instant )
{
tlog1 < < " Not supported call to CGameHandler::moveHero \n " ;
return ;
}
CGHeroInstance * h = const_cast < CGHeroInstance * > ( getHero ( hid ) ) ;
//check if destination tile is free
BOOST_FOREACH ( CGObjectInstance * obj , gs - > map - > terrain [ pos . x - 1 ] [ pos . y ] [ pos . z ] . blockingObjects )
{
if ( obj - > ID = = 34 )
{
if ( obj - > tempOwner = = h - > tempOwner )
return ; //TODO: exchange
//TODO: check for ally
CGHeroInstance * dh = static_cast < CGHeroInstance * > ( obj ) ;
startBattleI ( & h - > army , & dh - > army , pos , h , dh , 0 ) ;
return ;
}
}
TryMoveHero tmh ;
tmh . start = h - > pos ;
tmh . end = pos ;
tmh . id = hid ;
tmh . movePoints = h - > movement ;
tmh . result = instant + 1 ;
tmh . fowRevealed = gs - > tilesToReveal ( CGHeroInstance : : convertPosition ( pos , false ) , h - > getSightDistance ( ) , h - > tempOwner ) ;
sendAndApply ( & tmh ) ;
}
void CGameHandler : : setOwner ( int objid , ui8 owner )
{
SetObjectProperty sop ( objid , 1 , owner ) ;
sendAndApply ( & sop ) ;
}
void CGameHandler : : setHoverName ( int objid , MetaString * name )
{
SetHoverName shn ( objid , * name ) ;
sendAndApply ( & shn ) ;
}
void CGameHandler : : showInfoDialog ( InfoWindow * iw )
{
sendToAllClients ( iw ) ;
}
void CGameHandler : : showYesNoDialog ( YesNoDialog * iw , const CFunctionList < void ( ui32 ) > & callback )
{
ask ( iw , iw - > player , callback ) ;
}
void CGameHandler : : showSelectionDialog ( SelectionDialog * iw , const CFunctionList < void ( ui32 ) > & callback )
{
ask ( iw , iw - > player , callback ) ;
}
2008-12-27 03:01:59 +02:00
int CGameHandler : : getCurrentPlayer ( )
2008-12-22 19:48:41 +02:00
{
2008-12-27 03:01:59 +02:00
return gs - > currentPlayer ;
2008-12-22 19:48:41 +02:00
}
void CGameHandler : : giveResource ( int player , int which , int val )
{
SetResource sr ;
sr . player = player ;
sr . resid = which ;
sr . val = ( gs - > players . find ( player ) - > second . resources [ which ] + val ) ;
sendAndApply ( & sr ) ;
}
void CGameHandler : : showCompInfo ( ShowInInfobox * comp )
{
sendToAllClients ( comp ) ;
}
void CGameHandler : : heroVisitCastle ( int obj , int heroID )
{
HeroVisitCastle vc ;
vc . hid = heroID ;
vc . tid = obj ;
vc . flags | = 1 ;
sendAndApply ( & vc ) ;
giveSpells ( getTown ( obj ) , getHero ( heroID ) ) ;
}
void CGameHandler : : stopHeroVisitCastle ( int obj , int heroID )
{
HeroVisitCastle vc ;
vc . hid = heroID ;
vc . tid = obj ;
sendAndApply ( & vc ) ;
}
void CGameHandler : : giveHeroArtifact ( int artid , int hid , int position ) //pos==-1 - first free slot in backpack
{
const CGHeroInstance * h = getHero ( hid ) ;
SetHeroArtifacts sha ;
sha . hid = hid ;
sha . artifacts = h - > artifacts ;
sha . artifWorn = h - > artifWorn ;
if ( position < 0 )
{
if ( position = = - 2 )
{
int i ;
for ( i = 0 ; i < VLC - > arth - > artifacts [ artid ] . possibleSlots . size ( ) ; i + + ) //try to put artifact into first avaialble slot
{
if ( ! vstd : : contains ( sha . artifWorn , VLC - > arth - > artifacts [ artid ] . possibleSlots [ i ] ) )
{
sha . artifWorn [ VLC - > arth - > artifacts [ artid ] . possibleSlots [ i ] ] = artid ;
break ;
}
}
if ( i = = VLC - > arth - > artifacts [ artid ] . possibleSlots . size ( ) ) //if haven't find proper slot, use backpack
sha . artifacts . push_back ( artid ) ;
}
else //should be -1 => putartifact into backpack
{
sha . artifacts . push_back ( artid ) ;
}
}
else
{
if ( ! vstd : : contains ( sha . artifWorn , ui16 ( position ) ) )
sha . artifWorn [ position ] = artid ;
else
sha . artifacts . push_back ( artid ) ;
}
sendAndApply ( & sha ) ;
}
void CGameHandler : : startBattleI ( const CCreatureSet * army1 , const CCreatureSet * army2 , int3 tile , const CGHeroInstance * hero1 , const CGHeroInstance * hero2 , boost : : function < void ( BattleResult * ) > cb ) //use hero=NULL for no hero
{
boost : : thread ( boost : : bind ( & CGameHandler : : startBattle , this , * ( CCreatureSet * ) army1 , * ( CCreatureSet * ) army2 , tile , ( CGHeroInstance * ) hero1 , ( CGHeroInstance * ) hero2 , cb ) ) ;
}
void CGameHandler : : startBattleI ( int heroID , CCreatureSet army , int3 tile , boost : : function < void ( BattleResult * ) > cb ) //for hero<=>neutral army
{
CGHeroInstance * h = const_cast < CGHeroInstance * > ( getHero ( heroID ) ) ;
startBattleI ( & h - > army , & army , tile , h , NULL , cb ) ;
//battle(&h->army,army,tile,h,NULL);
}
void CGameHandler : : changeSpells ( int hid , bool give , const std : : set < ui32 > & spells )
{
ChangeSpells cs ;
cs . hid = hid ;
cs . spells = spells ;
cs . learn = give ;
sendAndApply ( & cs ) ;
}
2008-12-27 03:01:59 +02:00
int CGameHandler : : getSelectedHero ( )
2008-12-22 19:48:41 +02:00
{
2008-12-27 03:01:59 +02:00
return IGameCallback : : getSelectedHero ( getCurrentPlayer ( ) ) - > id ;
}
void CGameHandler : : setObjProperty ( int objid , int prop , int val )
{
SetObjectProperty sob ;
sob . id = objid ;
sob . what = prop ;
sob . val = val ;
sendAndApply ( & sob ) ;
2009-02-01 16:11:41 +02:00
}
void CGameHandler : : sendMessageTo ( CConnection & c , std : : string message )
{
c < < ui16 ( 95 ) < < message ;
2009-02-04 15:40:54 +02:00
}
void CGameHandler : : giveHeroBonus ( GiveBonus * bonus )
{
sendAndApply ( bonus ) ;
}
void CGameHandler : : setMovePoints ( SetMovePoints * smp )
{
sendAndApply ( smp ) ;
2009-02-06 13:15:39 +02:00
}
void CGameHandler : : setManaPoints ( int hid , int val )
{
SetMana sm ;
sm . hid = hid ;
sm . val = val ;
sendAndApply ( & sm ) ;
2008-12-22 19:48:41 +02:00
}