2008-07-25 20:28:28 +03:00
# include <boost/foreach.hpp>
# include <boost/thread.hpp>
# include <boost/thread/shared_mutex.hpp>
# include <boost/bind.hpp>
2008-07-01 11:01:02 +03:00
# include "CGameHandler.h"
2008-07-30 20:51:19 +03:00
# include "CScriptCallback.h"
2008-07-28 15:44:08 +03:00
# include "../CLua.h"
2008-07-25 20:28:28 +03:00
# include "../CGameState.h"
# include "../StartInfo.h"
# include "../map.h"
# include "../lib/NetPacks.h"
# include "../lib/Connection.h"
2008-08-27 13:19:18 +03:00
# include "../hch/CArtHandler.h"
2008-07-25 20:28:28 +03:00
# include "../hch/CObjectHandler.h"
# include "../hch/CTownHandler.h"
2008-08-01 14:21:15 +03:00
# include "../hch/CBuildingHandler.h"
2008-07-25 20:28:28 +03:00
# include "../hch/CHeroHandler.h"
2008-07-27 20:07:37 +03:00
# include "boost/date_time/posix_time/posix_time_types.hpp" //no i/o just types
2008-07-31 16:21:42 +03:00
# include "../lib/VCMI_Lib.h"
2008-08-04 18:56:36 +03:00
# include "../lib/CondSh.h"
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 :
bool operator ( ) ( const CStack * a , const CStack * b )
{
return ( a - > creature - > speed ) > ( b - > creature - > speed ) ;
}
} 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-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-07-30 20:51:19 +03: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 ] ) ;
}
void CGameHandler : : changeSecSkill ( int ID , ui16 which , int val , bool abs )
{
SetSecSkill sps ;
sps . id = ID ;
sps . which = which ;
sps . abs = abs ;
sps . val = val ;
sendAndApply ( & sps ) ;
}
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
std : : cout < < hero - > name < < " got level " < < hero - > level < < std : : endl ;
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 ;
}
std : : cout < < " Bohater dostaje umiejetnosc pierwszorzedna " < < x < < " (wynik losowania " < < r < < " ) " < < std : : endl ;
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 + + )
{
if ( hero - > secSkills [ i ] . second < 2 )
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-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 ;
if ( ( hero1 & & hero1 - > getSecSkillLevel ( 19 ) > = 0 ) | |
( hero2 & & hero2 - > getSecSkillLevel ( 19 ) > = 0 ) ) //someone has tactics
{
//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
for ( unsigned i = 0 ; i < stacks . size ( ) & & ! battleResult . get ( ) ; i + + )
{
2008-09-12 11:51:46 +03:00
if ( ! stacks [ i ] - > alive ( ) ) continue ; //indicates imposiibility of making action for this dead unit
2008-08-04 18:56:36 +03:00
BattleSetActiveStack sas ;
2008-08-05 02:04:15 +03:00
sas . stack = stacks [ i ] - > ID ;
2008-08-04 18:56:36 +03:00
sendAndApply ( & sas ) ;
boost : : unique_lock < boost : : mutex > lock ( battleMadeAction . mx ) ;
2008-09-12 11:51:46 +03:00
while ( ! battleMadeAction . data & & ! battleResult . get ( ) ) //active stack hasn't made its action and battle is still going
2008-08-04 18:56:36 +03:00
battleMadeAction . cond . wait ( lock ) ;
2008-08-05 02:04:15 +03:00
battleMadeAction . data = false ;
2008-09-12 11:51:46 +03:00
checkForBattleEnd ( stacks ) ; //check if this action ended the battle
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 )
states . setFlag ( hero2 - > tempOwner , & PlayerStatus : : engagedIntoBattle , false ) ;
2008-08-04 18:56:36 +03:00
//end battle, remove all info, free memory
sendAndApply ( battleResult . data ) ;
2008-09-12 11:51:46 +03:00
if ( cb )
cb ( battleResult . data ) ;
2008-08-04 18:56:36 +03:00
delete battleResult . data ;
//for(int i=0;i<stacks.size();i++)
// delete stacks[i];
//delete curB;
//curB = NULL;
}
2008-08-09 02:02:32 +03:00
void prepareAttack ( BattleAttack & bat , CStack * att , CStack * def )
{
bat . stackAttacking = att - > ID ;
bat . bsa . stackAttacked = def - > ID ;
bat . bsa . damageAmount = BattleInfo : : calculateDmg ( att , def ) ; //counting dealt damage
//applying damages
bat . bsa . killedAmount = bat . bsa . damageAmount / def - > creature - > hitPoints ;
unsigned damageFirst = bat . bsa . damageAmount % def - > creature - > hitPoints ;
if ( def - > firstHPleft < = damageFirst )
{
bat . bsa . killedAmount + + ;
bat . bsa . newHP = def - > firstHPleft + def - > creature - > hitPoints - damageFirst ;
}
else
{
bat . bsa . newHP = def - > firstHPleft - damageFirst ;
}
2008-08-04 18:56:36 +03:00
2008-08-09 02:02:32 +03:00
if ( def - > amount < = bat . bsa . killedAmount ) //stack killed
{
bat . bsa . newAmount = 0 ;
bat . bsa . flags | = 1 ;
2008-09-08 14:32:16 +03:00
bat . bsa . killedAmount = def - > amount ; //we cannot kill more creatures than we have
2008-08-09 02:02:32 +03:00
}
else
{
bat . bsa . newAmount = def - > amount - bat . bsa . killedAmount ;
}
}
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-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-08-02 00:41:38 +03:00
case 500 :
{
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 ;
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 ;
if ( ( h - > getOwner ( ) ! = gs - > currentPlayer ) | | //not turn of that hero
2008-07-29 12:53:27 +03:00
( distance ( start , end ) > = 1.5 ) | | //tiles are not neighouring
2008-07-28 15:44:08 +03:00
( 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
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-07-28 15:44:08 +03:00
if ( obj - > state ) //hard-coded function
2008-08-13 03:44:31 +03:00
obj - > state - > onHeroVisit ( obj - > id , h - > id ) ;
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
if ( obj - > state ) //hard-coded function
2008-08-13 03:44:31 +03:00
obj - > state - > onHeroLeave ( obj - > id , h - > id ) ;
2008-07-28 15:44:08 +03:00
}
//reveal fog of war
int heroSight = h - > getSightDistance ( ) ;
int xbeg = start . x - heroSight - 2 ;
if ( xbeg < 0 )
xbeg = 0 ;
int xend = start . x + heroSight + 2 ;
if ( xend > = gs - > map - > width )
xend = gs - > map - > width ;
int ybeg = start . y - heroSight - 2 ;
if ( ybeg < 0 )
ybeg = 0 ;
int yend = start . y + heroSight + 2 ;
if ( yend > = gs - > map - > height )
yend = gs - > map - > height ;
for ( int xd = xbeg ; xd < xend ; + + xd ) //revealing part of map around heroes
{
for ( int yd = ybeg ; yd < yend ; + + yd )
{
int deltaX = ( hmpos . x - xd ) * ( hmpos . x - xd ) ;
int deltaY = ( hmpos . y - yd ) * ( hmpos . y - yd ) ;
if ( deltaX + deltaY < h - > getSightDistance ( ) * h - > getSightDistance ( ) )
{
if ( gs - > players [ h - > getOwner ( ) ] . fogOfWarMap [ xd ] [ yd ] [ hmpos . z ] = = 0 )
{
tmh . fowRevealed . insert ( int3 ( xd , yd , hmpos . z ) ) ;
}
}
}
}
2008-07-30 20:51:19 +03:00
sendAndApply ( & tmh ) ;
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-07-28 15:44:08 +03:00
if ( obj - > state ) //hard-coded function
2008-07-30 20:51:19 +03:00
obj - > state - > onHeroVisit ( obj - > id , h - > id ) ;
2008-07-28 15:44:08 +03:00
}
}
break ;
fail :
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 ] ) ;
CCreatureSet * S1 = & s1 - > army , * S2 = & s2 - > army ;
if ( what = = 1 ) //swap
{
int pom = S2 - > slots [ p2 ] . first ;
S2 - > slots [ p2 ] . first = S1 - > slots [ p1 ] . first ;
S1 - > slots [ p1 ] . first = pom ;
int pom2 = S2 - > slots [ p2 ] . second ;
S2 - > slots [ p2 ] . second = S1 - > slots [ p1 ] . second ;
S1 - > slots [ p1 ] . second = pom2 ;
2008-08-25 13:25:16 +03:00
if ( ! S1 - > slots [ p1 ] . second )
2008-07-31 16:21:42 +03:00
S1 - > slots . erase ( p1 ) ;
2008-08-25 13:25:16 +03:00
if ( ! S2 - > slots [ p2 ] . second )
2008-07-31 16:21:42 +03:00
S2 - > slots . erase ( p2 ) ;
}
else if ( what = = 2 ) //merge
{
if ( S1 - > slots [ p1 ] . first ! = S2 - > slots [ p2 ] . first ) break ; //not same creature
S2 - > slots [ p2 ] . second + = S1 - > slots [ p1 ] . second ;
S1 - > slots [ p1 ] . first = NULL ;
S1 - > slots [ p1 ] . second = 0 ;
S1 - > slots . erase ( p1 ) ;
}
else if ( what = = 3 ) //split
{
si32 val ;
c > > val ;
if ( S2 - > slots . find ( p2 ) ! = S2 - > slots . end ( ) ) break ; //slot not free
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-08-20 22:02:48 +03:00
if ( ( s1 - > ID = = 34 & & ! S1 - > slots . size ( ) ) //it's not allowed to take last stack from hero army!
| | ( s2 - > ID = = 34 & & ! S2 - > slots . size ( ) ) )
{
break ;
}
2008-07-31 16:21:42 +03:00
SetGarrisons sg ;
sg . garrs [ id1 ] = * S1 ;
if ( s1 ! = s2 )
sg . garrs [ id2 ] = * S2 ;
sendAndApply ( & sg ) ;
2008-08-01 14:21:15 +03:00
break ;
}
case 503 :
{
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 ;
}
case 504 :
{
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
//TODO: check requirements
//TODO: check if building isn't forbidden
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
{
std : : cout < < " Warning, wrong garrison swap command for " < < tid < < std : : endl ;
}
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-08-25 13:25:16 +03:00
break ;
2008-08-20 22:02:48 +03:00
}
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 :
{
BattleAction ba ;
c > > ba ;
switch ( ba . actionType )
{
case 2 : //walk
{
2008-08-09 02:02:32 +03:00
moveStack ( ba . stackNumber , ba . destinationTile ) ;
2008-08-04 18:56:36 +03:00
break ;
}
case 3 : //defend
{
break ;
}
case 4 : //retreat/flee
{
//TODO: check if fleeing is possible (e.g. enemy may have Shackles of War)
//TODO: calculate casualties
//TODO: remove retreating hero from map and place it in recrutation list
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-08-04 18:56:36 +03:00
battleResult . set ( br ) ;
break ;
}
case 6 : //walk or 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 ) ;
if ( ( curStack - > position ! = ba . destinationTile ) | | //we wasn't able to reach destination tile
( BattleInfo : : mutualPosition ( ba . destinationTile , ba . additionalInfo ) < 0 ) ) //destination tile is not neighbouring with enemy stack
return ;
BattleAttack bat ;
prepareAttack ( bat , curStack , stackAtEnd ) ;
sendAndApply ( & bat ) ;
2008-09-12 11:51:46 +03:00
//counterattack
if ( ! vstd : : contains ( curStack - > abilities , NO_ENEMY_RETALIATION )
& & ! stackAtEnd - > counterAttacks ) //TODO: support for multiple retaliatons per turn
{
prepareAttack ( bat , stackAtEnd , curStack ) ;
bat . flags | = 2 ;
sendAndApply ( & bat ) ;
}
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 ) ;
BattleAttack bat ;
prepareAttack ( bat , curStack , destStack ) ;
bat . flags | = 1 ;
sendAndApply ( & bat ) ;
2008-08-04 18:56:36 +03:00
break ;
}
}
battleMadeAction . setn ( true ) ;
//sprawdzic czy po tej akcji ktoras strona nie wygrala bitwy
2008-07-31 16:21:42 +03:00
break ;
}
2008-07-27 20:07:37 +03:00
default :
2008-08-04 12:05:52 +03:00
# ifndef __GNUC__
2008-07-27 20:07:37 +03:00
throw std : : exception ( " Not supported client message! " ) ;
2008-08-04 12:05:52 +03:00
# else
throw std : : exception ( ) ;
# endif
2008-07-27 20:07:37 +03:00
break ;
}
2008-07-25 20:28:28 +03:00
}
}
2008-07-27 20:07:37 +03:00
catch ( const std : : exception & e )
{
std : : cerr < < e . what ( ) < < std : : endl ;
2008-08-04 12:05:52 +03:00
end2 = true ;
2008-07-27 20:07:37 +03:00
}
catch ( const std : : exception * e )
{
std : : cerr < < e - > what ( ) < < std : : endl ;
2008-08-04 12:05:52 +03:00
end2 = true ;
2008-07-27 20:07:37 +03:00
delete e ;
}
catch ( . . . )
{
2008-08-04 12:05:52 +03:00
end2 = true ;
2008-07-27 20:07:37 +03:00
}
2008-08-16 11:47:41 +03:00
handleConEnd :
;
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
bool accessibility [ 187 ] ;
if ( curStack - > creature - > isDoubleWide ( ) )
gs - > curB - > getAccessibilityMapForTwoHex ( accessibility , curStack - > attackerOwned , curStack - > ID ) ;
else
gs - > curB - > getAccessibilityMap ( accessibility , curStack - > ID ) ;
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 ) ;
int tilesToMove = std : : max ( ( int ) path . size ( ) - curStack - > creature - > speed , 0 ) ;
for ( int v = path . size ( ) - 1 ; v > = tilesToMove ; - - v )
{
//inform clients about move
BattleStackMoved sm ;
sm . stack = curStack - > ID ;
sm . tile = path [ v ] ;
if ( v = = path . size ( ) - 1 ) //move start - set flag
sm . flags | = 1 ;
if ( v = = 0 ) //move end - set flag
sm . flags | = 2 ;
sendAndApply ( & sm ) ;
}
}
2008-07-01 11:01:02 +03:00
CGameHandler : : CGameHandler ( void )
{
2008-07-25 20:28:28 +03:00
gs = NULL ;
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-07 06:38:37 +03:00
std : : cout < < " Map loaded! " < < std : : endl ;
2008-07-25 20:28:28 +03:00
gs = new CGameState ( ) ;
2008-09-07 06:38:37 +03:00
std : : cout < < " Gamestate created! " < < std : : endl ;
2008-07-30 20:51:19 +03:00
gs - > init ( si , map , Seed ) ;
2008-09-07 06:38:37 +03:00
std : : cout < < " Gamestate initialized! " < < std : : endl ;
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;
2008-07-01 11:01:02 +03:00
}
2008-07-25 20:28:28 +03:00
int lowestSpeed ( CGHeroInstance * chi )
{
2008-07-31 16:21:42 +03:00
std : : map < si32 , std : : pair < ui32 , si32 > > : : iterator i = chi - > army . slots . begin ( ) ;
int ret = VLC - > creh - > creatures [ ( * i + + ) . second . first ] . speed ;
2008-07-25 20:28:28 +03:00
for ( ; i ! = chi - > army . slots . end ( ) ; i + + )
{
2008-08-04 12:05:52 +03:00
ret = std : : min ( ret , VLC - > creh - > creatures [ ( * i ) . second . first ] . speed ) ;
2008-07-25 20:28:28 +03:00
}
return ret ;
}
int valMovePoints ( CGHeroInstance * chi )
{
int ret = 1270 + 70 * lowestSpeed ( chi ) ;
if ( ret > 2000 )
ret = 2000 ;
//TODO: additional bonuses (but they aren't currently stored in chi)
return ret ;
}
void CGameHandler : : newTurn ( )
{
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-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
for ( unsigned j = 0 ; j < ( * i ) . second . heroes . size ( ) ; j + + ) //handle heroes
2008-07-25 20:28:28 +03:00
{
2008-07-26 16:57:32 +03:00
NewTurn : : Hero h ;
h . id = ( * i ) . second . heroes [ j ] - > id ;
h . move = valMovePoints ( ( * i ) . second . heroes [ j ] ) ;
h . mana = ( * i ) . second . heroes [ j ] - > mana ;
n . heroes . insert ( h ) ;
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-07-31 13:35:22 +03:00
for ( std : : set < CCPPObjectScript * > : : iterator i = cppscripts . begin ( ) ; i ! = cppscripts . end ( ) ; i + + )
{
( * i ) - > newTurn ( ) ;
}
2008-07-25 20:28:28 +03:00
}
void CGameHandler : : run ( )
{
BOOST_FOREACH ( CConnection * cc , conns )
{ //init conn.
ui8 quantity , pom ;
//ui32 seed;
2008-07-26 09:39:44 +03:00
( * cc ) < < gs - > scenarioOps - > mapname < < gs - > map - > checksum < < gs - > seed ;
2008-07-25 20:28:28 +03:00
( * cc ) > > quantity ;
for ( int i = 0 ; i < quantity ; i + + )
{
( * cc ) > > pom ;
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************************************************/
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 ) ) ;
/****************************INITIALIZING OBJECT SCRIPTS************************************************/
//std::string temps("newObject");
for ( unsigned i = 0 ; i < gs - > map - > objects . size ( ) ; i + + )
{
//c++ scripts
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 ;
}
//// lua scripts
//if(checkFunc(map->objects[i]->ID,temps))
// (*skrypty)[map->objects[i]->ID][temps]->newObject(map->objects[i]);
}
2008-08-13 03:44:31 +03:00
for ( std : : map < ui8 , PlayerState > : : iterator i = gs - > players . begin ( ) ; i ! = gs - > players . end ( ) ; i + + )
states . addPlayer ( i - > first ) ;
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
{
2008-07-26 16:57:32 +03:00
newTurn ( ) ;
2008-07-25 20:28:28 +03:00
for ( std : : map < ui8 , PlayerState > : : iterator i = gs - > players . begin ( ) ; i ! = gs - > players . end ( ) ; i + + )
{
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
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 ) ) ;
2008-08-15 15:11:42 +03:00
stacks [ stacks . size ( ) - 1 ] - > ID = stacks . size ( ) - 1 ;
}
//initialization of positions
switch ( army1 . slots . size ( ) ) //for attacker
{
case 0 :
break ;
case 1 :
stacks [ 0 ] - > position = 86 ; //6
break ;
case 2 :
stacks [ 0 ] - > position = 35 ; //3
stacks [ 1 ] - > position = 137 ; //9
break ;
case 3 :
stacks [ 0 ] - > position = 35 ; //3
stacks [ 1 ] - > position = 86 ; //6
stacks [ 2 ] - > position = 137 ; //9
break ;
case 4 :
stacks [ 0 ] - > position = 1 ; //1
stacks [ 1 ] - > position = 69 ; //5
stacks [ 2 ] - > position = 103 ; //7
stacks [ 3 ] - > position = 171 ; //11
break ;
case 5 :
stacks [ 0 ] - > position = 1 ; //1
stacks [ 1 ] - > position = 35 ; //3
stacks [ 2 ] - > position = 86 ; //6
stacks [ 3 ] - > position = 137 ; //9
stacks [ 4 ] - > position = 171 ; //11
break ;
case 6 :
stacks [ 0 ] - > position = 1 ; //1
stacks [ 1 ] - > position = 35 ; //3
stacks [ 2 ] - > position = 69 ; //5
stacks [ 3 ] - > position = 103 ; //7
stacks [ 4 ] - > position = 137 ; //9
stacks [ 5 ] - > position = 171 ; //11
break ;
case 7 :
stacks [ 0 ] - > position = 1 ; //1
stacks [ 1 ] - > position = 35 ; //3
stacks [ 2 ] - > position = 69 ; //5
stacks [ 3 ] - > position = 86 ; //6
stacks [ 4 ] - > position = 103 ; //7
stacks [ 5 ] - > position = 137 ; //9
stacks [ 6 ] - > position = 171 ; //11
break ;
default : //fault
break ;
}
for ( std : : map < si32 , std : : pair < ui32 , si32 > > : : iterator i = army2 . slots . begin ( ) ; i ! = army2 . 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 , hero2 ? hero2 - > tempOwner : 255 , stacks . size ( ) , false , i - > first ) ) ;
2008-08-15 15:11:42 +03:00
switch ( army2 . slots . size ( ) ) //for defender
{
case 0 :
break ;
case 1 :
stacks [ 0 + army1 . slots . size ( ) ] - > position = 100 ; //6
break ;
case 2 :
stacks [ 0 + army1 . slots . size ( ) ] - > position = 49 ; //3
stacks [ 1 + army1 . slots . size ( ) ] - > position = 151 ; //9
break ;
case 3 :
stacks [ 0 + army1 . slots . size ( ) ] - > position = 49 ; //3
stacks [ 1 + army1 . slots . size ( ) ] - > position = 100 ; //6
stacks [ 2 + army1 . slots . size ( ) ] - > position = 151 ; //9
break ;
case 4 :
stacks [ 0 + army1 . slots . size ( ) ] - > position = 15 ; //1
stacks [ 1 + army1 . slots . size ( ) ] - > position = 83 ; //5
stacks [ 2 + army1 . slots . size ( ) ] - > position = 117 ; //7
stacks [ 3 + army1 . slots . size ( ) ] - > position = 185 ; //11
break ;
case 5 :
stacks [ 0 + army1 . slots . size ( ) ] - > position = 15 ; //1
stacks [ 1 + army1 . slots . size ( ) ] - > position = 49 ; //3
stacks [ 2 + army1 . slots . size ( ) ] - > position = 100 ; //6
stacks [ 3 + army1 . slots . size ( ) ] - > position = 151 ; //9
stacks [ 4 + army1 . slots . size ( ) ] - > position = 185 ; //11
break ;
case 6 :
stacks [ 0 + army1 . slots . size ( ) ] - > position = 15 ; //1
stacks [ 1 + army1 . slots . size ( ) ] - > position = 49 ; //3
stacks [ 2 + army1 . slots . size ( ) ] - > position = 83 ; //5
stacks [ 3 + army1 . slots . size ( ) ] - > position = 117 ; //7
stacks [ 4 + army1 . slots . size ( ) ] - > position = 151 ; //9
stacks [ 5 + army1 . slots . size ( ) ] - > position = 185 ; //11
break ;
case 7 :
stacks [ 0 + army1 . slots . size ( ) ] - > position = 15 ; //1
stacks [ 1 + army1 . slots . size ( ) ] - > position = 49 ; //3
stacks [ 2 + army1 . slots . size ( ) ] - > position = 83 ; //5
stacks [ 3 + army1 . slots . size ( ) ] - > position = 100 ; //6
stacks [ 4 + army1 . slots . size ( ) ] - > position = 117 ; //7
stacks [ 5 + army1 . slots . size ( ) ] - > position = 151 ; //9
stacks [ 6 + army1 . slots . size ( ) ] - > position = 185 ; //11
break ;
default : //fault
break ;
}
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 ;
}
}
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 + + )
{
for ( int j = 0 ; j < t - > spellsAtLevel ( i + 1 , true ) ; j + + )
{
if ( ! vstd : : contains ( h - > spells , t - > spells [ i ] [ j ] ) )
cs . spells . insert ( t - > spells [ i ] [ j ] ) ;
}
}
if ( cs . spells . size ( ) )
sendAndApply ( & cs ) ;
2008-09-09 10:05:02 +03:00
}