mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
* partially done duel mode
* program options parsing via boost::program_options * Stupid AI - a stupid battle-only AI * precompiled headers for server and Stupid AI on MSVC
This commit is contained in:
parent
49083c4e5a
commit
af2c4633ad
@ -473,19 +473,19 @@ bool CCallback::buildBuilding(const CGTownInstance *town, si32 buildingID)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CCallback::battleGetBattlefieldType()
|
int CBattleCallback::battleGetBattlefieldType()
|
||||||
{
|
{
|
||||||
boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||||
return gs->battleGetBattlefieldType();
|
return gs->battleGetBattlefieldType();
|
||||||
}
|
}
|
||||||
|
|
||||||
int CCallback::battleGetObstaclesAtTile(int tile) //returns bitfield
|
int CBattleCallback::battleGetObstaclesAtTile(int tile) //returns bitfield
|
||||||
{
|
{
|
||||||
//TODO - write
|
//TODO - write
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<CObstacleInstance> CCallback::battleGetAllObstacles()
|
std::vector<CObstacleInstance> CBattleCallback::battleGetAllObstacles()
|
||||||
{
|
{
|
||||||
boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||||
if(gs->curB)
|
if(gs->curB)
|
||||||
@ -494,14 +494,14 @@ std::vector<CObstacleInstance> CCallback::battleGetAllObstacles()
|
|||||||
return std::vector<CObstacleInstance>();
|
return std::vector<CObstacleInstance>();
|
||||||
}
|
}
|
||||||
|
|
||||||
const CStack* CCallback::battleGetStackByID(int ID, bool onlyAlive)
|
const CStack* CBattleCallback::battleGetStackByID(int ID, bool onlyAlive)
|
||||||
{
|
{
|
||||||
boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||||
if(!gs->curB) return NULL;
|
if(!gs->curB) return NULL;
|
||||||
return gs->curB->getStack(ID, onlyAlive);
|
return gs->curB->getStack(ID, onlyAlive);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CCallback::battleMakeAction(BattleAction* action)
|
int CBattleCallback::battleMakeAction(BattleAction* action)
|
||||||
{
|
{
|
||||||
assert(action->actionType == BattleAction::HERO_SPELL);
|
assert(action->actionType == BattleAction::HERO_SPELL);
|
||||||
MakeCustomAction mca(*action);
|
MakeCustomAction mca(*action);
|
||||||
@ -509,13 +509,13 @@ int CCallback::battleMakeAction(BattleAction* action)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CStack* CCallback::battleGetStackByPos(int pos, bool onlyAlive)
|
const CStack* CBattleCallback::battleGetStackByPos(int pos, bool onlyAlive)
|
||||||
{
|
{
|
||||||
boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||||
return battleGetStackByID(gs->battleGetStack(pos, onlyAlive), onlyAlive);
|
return battleGetStackByID(gs->battleGetStack(pos, onlyAlive), onlyAlive);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CCallback::battleGetPos(int stack)
|
int CBattleCallback::battleGetPos(int stack)
|
||||||
{
|
{
|
||||||
boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||||
if(!gs->curB)
|
if(!gs->curB)
|
||||||
@ -531,7 +531,7 @@ int CCallback::battleGetPos(int stack)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<const CStack*> CCallback::battleGetStacks()
|
std::vector<const CStack*> CBattleCallback::battleGetStacks()
|
||||||
{
|
{
|
||||||
boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||||
std::vector<const CStack*> ret;
|
std::vector<const CStack*> ret;
|
||||||
@ -547,7 +547,7 @@ std::vector<const CStack*> CCallback::battleGetStacks()
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCallback::getStackQueue( std::vector<const CStack *> &out, int howMany )
|
void CBattleCallback::getStackQueue( std::vector<const CStack *> &out, int howMany )
|
||||||
{
|
{
|
||||||
if(!gs->curB)
|
if(!gs->curB)
|
||||||
{
|
{
|
||||||
@ -557,7 +557,7 @@ void CCallback::getStackQueue( std::vector<const CStack *> &out, int howMany )
|
|||||||
gs->curB->getStackQueue(out, howMany);
|
gs->curB->getStackQueue(out, howMany);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<int> CCallback::battleGetAvailableHexes(int ID, bool addOccupiable)
|
std::vector<int> CBattleCallback::battleGetAvailableHexes(int ID, bool addOccupiable)
|
||||||
{
|
{
|
||||||
boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||||
if(!gs->curB)
|
if(!gs->curB)
|
||||||
@ -569,7 +569,7 @@ std::vector<int> CCallback::battleGetAvailableHexes(int ID, bool addOccupiable)
|
|||||||
//return gs->battleGetRange(ID);
|
//return gs->battleGetRange(ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CCallback::battleCanShoot(int ID, int dest)
|
bool CBattleCallback::battleCanShoot(int ID, int dest)
|
||||||
{
|
{
|
||||||
boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||||
|
|
||||||
@ -578,7 +578,7 @@ bool CCallback::battleCanShoot(int ID, int dest)
|
|||||||
return gs->battleCanShoot(ID, dest);
|
return gs->battleCanShoot(ID, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CCallback::battleCanCastSpell()
|
bool CBattleCallback::battleCanCastSpell()
|
||||||
{
|
{
|
||||||
if(!gs->curB) //there is no battle
|
if(!gs->curB) //there is no battle
|
||||||
return false;
|
return false;
|
||||||
@ -589,12 +589,12 @@ bool CCallback::battleCanCastSpell()
|
|||||||
return gs->curB->castSpells[1] == 0 && gs->curB->heroes[1] && gs->curB->heroes[1]->getArt(17);
|
return gs->curB->castSpells[1] == 0 && gs->curB->heroes[1] && gs->curB->heroes[1]->getArt(17);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CCallback::battleCanFlee()
|
bool CBattleCallback::battleCanFlee()
|
||||||
{
|
{
|
||||||
return gs->battleCanFlee(player);
|
return gs->battleCanFlee(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
const CGTownInstance *CCallback::battleGetDefendedTown()
|
const CGTownInstance *CBattleCallback::battleGetDefendedTown()
|
||||||
{
|
{
|
||||||
if(!gs->curB || gs->curB->tid == -1)
|
if(!gs->curB || gs->curB->tid == -1)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -602,7 +602,7 @@ const CGTownInstance *CCallback::battleGetDefendedTown()
|
|||||||
return static_cast<const CGTownInstance *>(gs->map->objects[gs->curB->tid].get());
|
return static_cast<const CGTownInstance *>(gs->map->objects[gs->curB->tid].get());
|
||||||
}
|
}
|
||||||
|
|
||||||
ui8 CCallback::battleGetWallState(int partOfWall)
|
ui8 CBattleCallback::battleGetWallState(int partOfWall)
|
||||||
{
|
{
|
||||||
if(!gs->curB || gs->curB->siege == 0)
|
if(!gs->curB || gs->curB->siege == 0)
|
||||||
{
|
{
|
||||||
@ -611,7 +611,7 @@ ui8 CCallback::battleGetWallState(int partOfWall)
|
|||||||
return gs->curB->si.wallState[partOfWall];
|
return gs->curB->si.wallState[partOfWall];
|
||||||
}
|
}
|
||||||
|
|
||||||
int CCallback::battleGetWallUnderHex(int hex)
|
int CBattleCallback::battleGetWallUnderHex(int hex)
|
||||||
{
|
{
|
||||||
if(!gs->curB || gs->curB->siege == 0)
|
if(!gs->curB || gs->curB->siege == 0)
|
||||||
{
|
{
|
||||||
@ -620,7 +620,7 @@ int CCallback::battleGetWallUnderHex(int hex)
|
|||||||
return gs->curB->hexToWallPart(hex);
|
return gs->curB->hexToWallPart(hex);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<ui32, ui32> CCallback::battleEstimateDamage(int attackerID, int defenderID)
|
std::pair<ui32, ui32> CBattleCallback::battleEstimateDamage(int attackerID, int defenderID)
|
||||||
{
|
{
|
||||||
if(!gs->curB)
|
if(!gs->curB)
|
||||||
return std::make_pair(0, 0);
|
return std::make_pair(0, 0);
|
||||||
@ -644,7 +644,7 @@ std::pair<ui32, ui32> CCallback::battleEstimateDamage(int attackerID, int defend
|
|||||||
return gs->curB->calculateDmgRange(attacker, defender, attackerHero, defenderHero, battleCanShoot(attacker->ID, defender->position), 0, false);
|
return gs->curB->calculateDmgRange(attacker, defender, attackerHero, defenderHero, battleCanShoot(attacker->ID, defender->position), 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
ui8 CCallback::battleGetSiegeLevel()
|
ui8 CBattleCallback::battleGetSiegeLevel()
|
||||||
{
|
{
|
||||||
if(!gs->curB)
|
if(!gs->curB)
|
||||||
return 0;
|
return 0;
|
||||||
@ -652,7 +652,7 @@ ui8 CCallback::battleGetSiegeLevel()
|
|||||||
return gs->curB->siege;
|
return gs->curB->siege;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CGHeroInstance * CCallback::battleGetFightingHero(ui8 side) const
|
const CGHeroInstance * CBattleCallback::battleGetFightingHero(ui8 side) const
|
||||||
{
|
{
|
||||||
if(!gs->curB)
|
if(!gs->curB)
|
||||||
return 0;
|
return 0;
|
||||||
@ -660,6 +660,19 @@ const CGHeroInstance * CCallback::battleGetFightingHero(ui8 side) const
|
|||||||
return gs->curB->heroes[side];
|
return gs->curB->heroes[side];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void CBattleCallback::sendRequest(const T* request)
|
||||||
|
{
|
||||||
|
//TODO? should be part of CClient but it would have to be very tricky cause template/serialization issues
|
||||||
|
if(waitTillRealize)
|
||||||
|
cl->waitingRequest.set(true);
|
||||||
|
|
||||||
|
*cl->serv << request;
|
||||||
|
|
||||||
|
if(waitTillRealize)
|
||||||
|
cl->waitingRequest.waitWhileTrue();
|
||||||
|
}
|
||||||
|
|
||||||
void CCallback::swapGarrisonHero( const CGTownInstance *town )
|
void CCallback::swapGarrisonHero( const CGTownInstance *town )
|
||||||
{
|
{
|
||||||
if(town->tempOwner != player) return;
|
if(town->tempOwner != player) return;
|
||||||
@ -822,21 +835,8 @@ void CCallback::buildBoat( const IShipyard *obj )
|
|||||||
sendRequest(&bb);
|
sendRequest(&bb);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void CCallback::sendRequest(const T* request)
|
|
||||||
{
|
|
||||||
//TODO? should be part of CClient but it would have to be very tricky cause template/serialization issues
|
|
||||||
if(waitTillRealize)
|
|
||||||
cl->waitingRequest.set(true);
|
|
||||||
|
|
||||||
*cl->serv << request;
|
|
||||||
|
|
||||||
if(waitTillRealize)
|
|
||||||
cl->waitingRequest.waitWhileTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
CCallback::CCallback( CGameState * GS, int Player, CClient *C )
|
CCallback::CCallback( CGameState * GS, int Player, CClient *C )
|
||||||
:gs(GS), cl(C), player(Player)
|
:CBattleCallback(GS, Player, C)
|
||||||
{
|
{
|
||||||
waitTillRealize = false;
|
waitTillRealize = false;
|
||||||
}
|
}
|
||||||
@ -909,17 +909,17 @@ bool CCallback::hasAccess(int playerId) const
|
|||||||
return gs->getPlayerRelations( playerId, player ) || player < 0;
|
return gs->getPlayerRelations( playerId, player ) || player < 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
si8 CCallback::battleHasDistancePenalty( int stackID, int destHex )
|
si8 CBattleCallback::battleHasDistancePenalty( int stackID, int destHex )
|
||||||
{
|
{
|
||||||
return gs->curB->hasDistancePenalty(stackID, destHex);
|
return gs->curB->hasDistancePenalty(stackID, destHex);
|
||||||
}
|
}
|
||||||
|
|
||||||
si8 CCallback::battleHasWallPenalty( int stackID, int destHex )
|
si8 CBattleCallback::battleHasWallPenalty( int stackID, int destHex )
|
||||||
{
|
{
|
||||||
return gs->curB->hasWallPenalty(stackID, destHex);
|
return gs->curB->hasWallPenalty(stackID, destHex);
|
||||||
}
|
}
|
||||||
|
|
||||||
si8 CCallback::battleCanTeleportTo(int stackID, int destHex, int telportLevel)
|
si8 CBattleCallback::battleCanTeleportTo(int stackID, int destHex, int telportLevel)
|
||||||
{
|
{
|
||||||
return gs->curB->canTeleportTo(stackID, destHex, telportLevel);
|
return gs->curB->canTeleportTo(stackID, destHex, telportLevel);
|
||||||
}
|
}
|
||||||
@ -1020,3 +1020,15 @@ void InfoAboutTown::initFromGarrison(const CGGarrison *garr, bool detailed)
|
|||||||
details->hallLevel = -1;
|
details->hallLevel = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CBattleCallback::hasAccess( int playerId ) const
|
||||||
|
{
|
||||||
|
return playerId == player || player < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CBattleCallback::CBattleCallback(CGameState *GS, int Player, CClient *C )
|
||||||
|
{
|
||||||
|
gs = GS;
|
||||||
|
player = Player;
|
||||||
|
cl = C;
|
||||||
|
}
|
126
CCallback.h
126
CCallback.h
@ -69,10 +69,37 @@ struct InfoAboutTown
|
|||||||
void initFromGarrison(const CGGarrison *garr, bool detailed);
|
void initFromGarrison(const CGGarrison *garr, bool detailed);
|
||||||
};
|
};
|
||||||
|
|
||||||
class ICallback
|
class IBattleCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
bool waitTillRealize; //if true, request functions will return after they are realized by server
|
bool waitTillRealize; //if true, request functions will return after they are realized by server
|
||||||
|
//battle
|
||||||
|
virtual int battleGetBattlefieldType()=0; // 1. sand/shore 2. sand/mesas 3. dirt/birches 4. dirt/hills 5. dirt/pines 6. grass/hills 7. grass/pines 8. lava 9. magic plains 10. snow/mountains 11. snow/trees 12. subterranean 13. swamp/trees 14. fiery fields 15. rock lands 16. magic clouds 17. lucid pools 18. holy ground 19. clover field 20. evil fog 21. "favourable winds" text on magic plains background 22. cursed ground 23. rough 24. ship to ship 25. ship
|
||||||
|
virtual int battleGetObstaclesAtTile(int tile)=0; //returns bitfield
|
||||||
|
virtual std::vector<CObstacleInstance> battleGetAllObstacles()=0; //returns all obstacles on the battlefield
|
||||||
|
virtual const CStack * battleGetStackByID(int ID, bool onlyAlive = true)=0; //returns stack info by given ID
|
||||||
|
virtual const CStack * battleGetStackByPos(int pos, bool onlyAlive = true)=0; //returns stack info by given pos
|
||||||
|
virtual int battleGetPos(int stack)=0; //returns position (tile ID) of stack
|
||||||
|
virtual int battleMakeAction(BattleAction* action)=0;//for casting spells by hero - DO NOT use it for moving active stack
|
||||||
|
virtual std::vector<const CStack*> battleGetStacks()=0; //returns stacks on battlefield
|
||||||
|
virtual void getStackQueue( std::vector<const CStack *> &out, int howMany )=0; //returns vector of stack in order of their move sequence
|
||||||
|
virtual std::vector<int> battleGetAvailableHexes(int ID, bool addOccupiable)=0; //returns numbers of hexes reachable by creature with id ID
|
||||||
|
virtual bool battleCanShoot(int ID, int dest)=0; //returns true if unit with id ID can shoot to dest
|
||||||
|
virtual bool battleCanCastSpell()=0; //returns true, if caller can cast a spell
|
||||||
|
virtual bool battleCanFlee()=0; //returns true if caller can flee from the battle
|
||||||
|
virtual const CGTownInstance * battleGetDefendedTown()=0; //returns defended town if current battle is a siege, NULL instead
|
||||||
|
virtual ui8 battleGetWallState(int partOfWall)=0; //for determining state of a part of the wall; format: parameter [0] - keep, [1] - bottom tower, [2] - bottom wall, [3] - below gate, [4] - over gate, [5] - upper wall, [6] - uppert tower, [7] - gate; returned value: 1 - intact, 2 - damaged, 3 - destroyed; 0 - no battle
|
||||||
|
virtual int battleGetWallUnderHex(int hex)=0; //returns part of destructible wall / gate / keep under given hex or -1 if not found
|
||||||
|
virtual std::pair<ui32, ui32> battleEstimateDamage(int attackerID, int defenderID)=0; //estimates damage dealt by attacker to defender; it may be not precise especially when stack has randomly working bonuses; returns pair <min dmg, max dmg>
|
||||||
|
virtual ui8 battleGetSiegeLevel()=0; //returns 0 when there is no siege, 1 if fort, 2 is citadel, 3 is castle
|
||||||
|
virtual const CGHeroInstance * battleGetFightingHero(ui8 side) const =0; //returns hero corresponding to given side (0 - attacker, 1 - defender)
|
||||||
|
virtual si8 battleHasDistancePenalty(int stackID, int destHex) =0; //checks if given stack has distance penalty
|
||||||
|
virtual si8 battleHasWallPenalty(int stackID, int destHex) =0; //checks if given stack has wall penalty
|
||||||
|
};
|
||||||
|
|
||||||
|
class ICallback : public virtual IBattleCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
//hero
|
//hero
|
||||||
virtual bool moveHero(const CGHeroInstance *h, int3 dst) =0; //dst must be free, neighbouring tile (this function can move hero only by one tile)
|
virtual bool moveHero(const CGHeroInstance *h, int3 dst) =0; //dst must be free, neighbouring tile (this function can move hero only by one tile)
|
||||||
virtual bool dismissHero(const CGHeroInstance * hero)=0; //dismisses given hero; true - successfuly, false - not successfuly
|
virtual bool dismissHero(const CGHeroInstance * hero)=0; //dismisses given hero; true - successfuly, false - not successfuly
|
||||||
@ -156,45 +183,59 @@ public:
|
|||||||
virtual int3 getMapSize() const =0; //returns size of map - z is 1 for one - level map and 2 for two level map
|
virtual int3 getMapSize() const =0; //returns size of map - z is 1 for one - level map and 2 for two level map
|
||||||
virtual const TerrainTile * getTileInfo(int3 tile) const = 0;
|
virtual const TerrainTile * getTileInfo(int3 tile) const = 0;
|
||||||
virtual int getPlayerRelations(ui8 color1, ui8 color2) const =0;// 0 = enemy, 1 = ally, 2 = same player
|
virtual int getPlayerRelations(ui8 color1, ui8 color2) const =0;// 0 = enemy, 1 = ally, 2 = same player
|
||||||
|
|
||||||
//battle
|
|
||||||
virtual int battleGetBattlefieldType()=0; // 1. sand/shore 2. sand/mesas 3. dirt/birches 4. dirt/hills 5. dirt/pines 6. grass/hills 7. grass/pines 8. lava 9. magic plains 10. snow/mountains 11. snow/trees 12. subterranean 13. swamp/trees 14. fiery fields 15. rock lands 16. magic clouds 17. lucid pools 18. holy ground 19. clover field 20. evil fog 21. "favourable winds" text on magic plains background 22. cursed ground 23. rough 24. ship to ship 25. ship
|
|
||||||
virtual int battleGetObstaclesAtTile(int tile)=0; //returns bitfield
|
|
||||||
virtual std::vector<CObstacleInstance> battleGetAllObstacles()=0; //returns all obstacles on the battlefield
|
|
||||||
virtual const CStack * battleGetStackByID(int ID, bool onlyAlive = true)=0; //returns stack info by given ID
|
|
||||||
virtual const CStack * battleGetStackByPos(int pos, bool onlyAlive = true)=0; //returns stack info by given pos
|
|
||||||
virtual int battleGetPos(int stack)=0; //returns position (tile ID) of stack
|
|
||||||
virtual int battleMakeAction(BattleAction* action)=0;//for casting spells by hero - DO NOT use it for moving active stack
|
|
||||||
virtual std::vector<const CStack*> battleGetStacks()=0; //returns stacks on battlefield
|
|
||||||
virtual void getStackQueue( std::vector<const CStack *> &out, int howMany )=0; //returns vector of stack in order of their move sequence
|
|
||||||
virtual std::vector<int> battleGetAvailableHexes(int ID, bool addOccupiable)=0; //returns numbers of hexes reachable by creature with id ID
|
|
||||||
virtual bool battleCanShoot(int ID, int dest)=0; //returns true if unit with id ID can shoot to dest
|
|
||||||
virtual bool battleCanCastSpell()=0; //returns true, if caller can cast a spell
|
|
||||||
virtual bool battleCanFlee()=0; //returns true if caller can flee from the battle
|
|
||||||
virtual const CGTownInstance * battleGetDefendedTown()=0; //returns defended town if current battle is a siege, NULL instead
|
|
||||||
virtual ui8 battleGetWallState(int partOfWall)=0; //for determining state of a part of the wall; format: parameter [0] - keep, [1] - bottom tower, [2] - bottom wall, [3] - below gate, [4] - over gate, [5] - upper wall, [6] - uppert tower, [7] - gate; returned value: 1 - intact, 2 - damaged, 3 - destroyed; 0 - no battle
|
|
||||||
virtual int battleGetWallUnderHex(int hex)=0; //returns part of destructible wall / gate / keep under given hex or -1 if not found
|
|
||||||
virtual std::pair<ui32, ui32> battleEstimateDamage(int attackerID, int defenderID)=0; //estimates damage dealt by attacker to defender; it may be not precise especially when stack has randomly working bonuses; returns pair <min dmg, max dmg>
|
|
||||||
virtual ui8 battleGetSiegeLevel()=0; //returns 0 when there is no siege, 1 if fort, 2 is citadel, 3 is castle
|
|
||||||
virtual const CGHeroInstance * battleGetFightingHero(ui8 side) const =0; //returns hero corresponding to given side (0 - attacker, 1 - defender)
|
|
||||||
virtual si8 battleHasDistancePenalty(int stackID, int destHex) =0; //checks if given stack has distance penalty
|
|
||||||
virtual si8 battleHasWallPenalty(int stackID, int destHex) =0; //checks if given stack has wall penalty
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CCallback : public ICallback
|
class CBattleCallback : public virtual IBattleCallback
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
CCallback(CGameState * GS, int Player, CClient *C);;
|
|
||||||
CGameState * gs;
|
CGameState * gs;
|
||||||
CClient *cl;
|
CBattleCallback(CGameState *GS, int Player, CClient *C);
|
||||||
bool isVisible(int3 pos, int Player) const;
|
|
||||||
bool isVisible(const CGObjectInstance *obj, int Player) const;
|
|
||||||
template <typename T> void sendRequest(const T*request);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool hasAccess(int playerId) const;
|
template <typename T> void sendRequest(const T*request);
|
||||||
|
CClient *cl;
|
||||||
|
virtual bool hasAccess(int playerId) const;
|
||||||
int player;
|
int player;
|
||||||
|
|
||||||
|
public:
|
||||||
|
//battle
|
||||||
|
int battleGetBattlefieldType(); // 1. sand/shore 2. sand/mesas 3. dirt/birches 4. dirt/hills 5. dirt/pines 6. grass/hills 7. grass/pines 8. lava 9. magic plains 10. snow/mountains 11. snow/trees 12. subterranean 13. swamp/trees 14. fiery fields 15. rock lands 16. magic clouds 17. lucid pools 18. holy ground 19. clover field 20. evil fog 21. "favourable winds" text on magic plains background 22. cursed ground 23. rough 24. ship to ship 25. ship
|
||||||
|
int battleGetObstaclesAtTile(int tile); //returns bitfield
|
||||||
|
std::vector<CObstacleInstance> battleGetAllObstacles(); //returns all obstacles on the battlefield
|
||||||
|
const CStack * battleGetStackByID(int ID, bool onlyAlive = true); //returns stack info by given ID
|
||||||
|
const CStack * battleGetStackByPos(int pos, bool onlyAlive = true); //returns stack info by given pos
|
||||||
|
int battleGetPos(int stack); //returns position (tile ID) of stack
|
||||||
|
int battleMakeAction(BattleAction* action);//for casting spells by hero - DO NOT use it for moving active stack
|
||||||
|
std::vector<const CStack*> battleGetStacks(); //returns stacks on battlefield
|
||||||
|
void getStackQueue( std::vector<const CStack *> &out, int howMany ); //returns vector of stack in order of their move sequence
|
||||||
|
std::vector<int> battleGetAvailableHexes(int ID, bool addOccupiable); //reutrns numbers of hexes reachable by creature with id ID
|
||||||
|
bool battleCanShoot(int ID, int dest); //returns true if unit with id ID can shoot to dest
|
||||||
|
bool battleCanCastSpell(); //returns true, if caller can cast a spell
|
||||||
|
bool battleCanFlee(); //returns true if caller can flee from the battle
|
||||||
|
const CGTownInstance * battleGetDefendedTown(); //returns defended town if current battle is a siege, NULL instead
|
||||||
|
ui8 battleGetWallState(int partOfWall); //for determining state of a part of the wall; format: parameter [0] - keep, [1] - bottom tower, [2] - bottom wall, [3] - below gate, [4] - over gate, [5] - upper wall, [6] - uppert tower, [7] - gate; returned value: 1 - intact, 2 - damaged, 3 - destroyed; 0 - no battle
|
||||||
|
int battleGetWallUnderHex(int hex); //returns part of destructible wall / gate / keep under given hex or -1 if not found
|
||||||
|
std::pair<ui32, ui32> battleEstimateDamage(int attackerID, int defenderID); //estimates damage dealt by attacker to defender; it may be not precise especially when stack has randomly working bonuses; returns pair <min dmg, max dmg>
|
||||||
|
ui8 battleGetSiegeLevel(); //returns 0 when there is no siege, 1 if fort, 2 is citadel, 3 is castle
|
||||||
|
const CGHeroInstance * battleGetFightingHero(ui8 side) const; //returns hero corresponding ot given side (0 - attacker, 1 - defender)
|
||||||
|
si8 battleHasDistancePenalty(int stackID, int destHex); //checks if given stack has distance penalty
|
||||||
|
si8 battleHasWallPenalty(int stackID, int destHex); //checks if given stack has wall penalty
|
||||||
|
si8 battleCanTeleportTo(int stackID, int destHex, int telportLevel); //checks if teleportation of given stack to given position can take place
|
||||||
|
|
||||||
|
friend CCallback;
|
||||||
|
friend CClient;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CCallback : public ICallback, public CBattleCallback
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
CCallback(CGameState * GS, int Player, CClient *C);
|
||||||
|
bool isVisible(int3 pos, int Player) const;
|
||||||
|
bool isVisible(const CGObjectInstance *obj, int Player) const;
|
||||||
|
protected:
|
||||||
|
virtual bool hasAccess(int playerId) const OVERRIDE;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//commands
|
//commands
|
||||||
bool moveHero(const CGHeroInstance *h, int3 dst); //dst must be free, neighbouring tile (this function can move hero only by one tile)
|
bool moveHero(const CGHeroInstance *h, int3 dst); //dst must be free, neighbouring tile (this function can move hero only by one tile)
|
||||||
@ -272,29 +313,6 @@ public:
|
|||||||
int getPlayerStatus(int player) const;
|
int getPlayerStatus(int player) const;
|
||||||
int getPlayerRelations(ui8 color1, ui8 color2) const;// 0 = enemy, 1 = ally, 2 = same player
|
int getPlayerRelations(ui8 color1, ui8 color2) const;// 0 = enemy, 1 = ally, 2 = same player
|
||||||
|
|
||||||
//battle
|
|
||||||
int battleGetBattlefieldType(); // 1. sand/shore 2. sand/mesas 3. dirt/birches 4. dirt/hills 5. dirt/pines 6. grass/hills 7. grass/pines 8. lava 9. magic plains 10. snow/mountains 11. snow/trees 12. subterranean 13. swamp/trees 14. fiery fields 15. rock lands 16. magic clouds 17. lucid pools 18. holy ground 19. clover field 20. evil fog 21. "favourable winds" text on magic plains background 22. cursed ground 23. rough 24. ship to ship 25. ship
|
|
||||||
int battleGetObstaclesAtTile(int tile); //returns bitfield
|
|
||||||
std::vector<CObstacleInstance> battleGetAllObstacles(); //returns all obstacles on the battlefield
|
|
||||||
const CStack * battleGetStackByID(int ID, bool onlyAlive = true); //returns stack info by given ID
|
|
||||||
const CStack * battleGetStackByPos(int pos, bool onlyAlive = true); //returns stack info by given pos
|
|
||||||
int battleGetPos(int stack); //returns position (tile ID) of stack
|
|
||||||
int battleMakeAction(BattleAction* action);//for casting spells by hero - DO NOT use it for moving active stack
|
|
||||||
std::vector<const CStack*> battleGetStacks(); //returns stacks on battlefield
|
|
||||||
void getStackQueue( std::vector<const CStack *> &out, int howMany ); //returns vector of stack in order of their move sequence
|
|
||||||
std::vector<int> battleGetAvailableHexes(int ID, bool addOccupiable); //reutrns numbers of hexes reachable by creature with id ID
|
|
||||||
bool battleCanShoot(int ID, int dest); //returns true if unit with id ID can shoot to dest
|
|
||||||
bool battleCanCastSpell(); //returns true, if caller can cast a spell
|
|
||||||
bool battleCanFlee(); //returns true if caller can flee from the battle
|
|
||||||
const CGTownInstance * battleGetDefendedTown(); //returns defended town if current battle is a siege, NULL instead
|
|
||||||
ui8 battleGetWallState(int partOfWall); //for determining state of a part of the wall; format: parameter [0] - keep, [1] - bottom tower, [2] - bottom wall, [3] - below gate, [4] - over gate, [5] - upper wall, [6] - uppert tower, [7] - gate; returned value: 1 - intact, 2 - damaged, 3 - destroyed; 0 - no battle
|
|
||||||
int battleGetWallUnderHex(int hex); //returns part of destructible wall / gate / keep under given hex or -1 if not found
|
|
||||||
std::pair<ui32, ui32> battleEstimateDamage(int attackerID, int defenderID); //estimates damage dealt by attacker to defender; it may be not precise especially when stack has randomly working bonuses; returns pair <min dmg, max dmg>
|
|
||||||
ui8 battleGetSiegeLevel(); //returns 0 when there is no siege, 1 if fort, 2 is citadel, 3 is castle
|
|
||||||
const CGHeroInstance * battleGetFightingHero(ui8 side) const; //returns hero corresponding ot given side (0 - attacker, 1 - defender)
|
|
||||||
si8 battleHasDistancePenalty(int stackID, int destHex); //checks if given stack has distance penalty
|
|
||||||
si8 battleHasWallPenalty(int stackID, int destHex); //checks if given stack has wall penalty
|
|
||||||
si8 battleCanTeleportTo(int stackID, int destHex, int telportLevel); //checks if teleportation of given stack to given position can take place
|
|
||||||
|
|
||||||
//XXX hmmm _tmain on _GNUC_ wtf?
|
//XXX hmmm _tmain on _GNUC_ wtf?
|
||||||
//friends
|
//friends
|
||||||
|
@ -18,17 +18,18 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
CGlobalAI * CAIHandler::getNewAI(CCallback * cb, std::string dllname)
|
template<typename rett>
|
||||||
|
rett * createAnyAI(CCallback * cb, std::string dllname, std::string methodName)
|
||||||
{
|
{
|
||||||
char temp[50];
|
char temp[50];
|
||||||
CGlobalAI * ret=NULL;
|
rett * ret=NULL;
|
||||||
CGlobalAI*(*getAI)();
|
rett*(*getAI)();
|
||||||
void(*getName)(char*);
|
void(*getName)(char*);
|
||||||
|
|
||||||
std::string dllPath;
|
std::string dllPath;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
dllPath = "AI/"+dllname+".dll";
|
dllPath = LIB_DIR "/" +dllname+".dll";
|
||||||
HINSTANCE dll = LoadLibraryA(dllPath.c_str());
|
HINSTANCE dll = LoadLibraryA(dllPath.c_str());
|
||||||
if (!dll)
|
if (!dll)
|
||||||
{
|
{
|
||||||
@ -37,7 +38,7 @@ CGlobalAI * CAIHandler::getNewAI(CCallback * cb, std::string dllname)
|
|||||||
}
|
}
|
||||||
//int len = dllname.size()+1;
|
//int len = dllname.size()+1;
|
||||||
getName = (void(*)(char*))GetProcAddress(dll,"GetAiName");
|
getName = (void(*)(char*))GetProcAddress(dll,"GetAiName");
|
||||||
getAI = (CGlobalAI*(*)())GetProcAddress(dll,"GetNewAI");
|
getAI = (rett*(*)())GetProcAddress(dll,methodName.c_str());
|
||||||
#else
|
#else
|
||||||
dllPath = LIB_DIR "/" + dllname + ".so";
|
dllPath = LIB_DIR "/" + dllname + ".so";
|
||||||
void *dll = dlopen(dllPath.c_str(), RTLD_LOCAL | RTLD_LAZY);
|
void *dll = dlopen(dllPath.c_str(), RTLD_LOCAL | RTLD_LAZY);
|
||||||
@ -47,7 +48,7 @@ CGlobalAI * CAIHandler::getNewAI(CCallback * cb, std::string dllname)
|
|||||||
throw new std::string("Cannot open AI library");
|
throw new std::string("Cannot open AI library");
|
||||||
}
|
}
|
||||||
getName = (void(*)(char*))dlsym(dll,"GetAiName");
|
getName = (void(*)(char*))dlsym(dll,"GetAiName");
|
||||||
getAI = (CGlobalAI*(*)())dlsym(dll,"GetNewAI");
|
getAI = (rett*(*)())dlsym(dll,methodName.c_str());
|
||||||
#endif
|
#endif
|
||||||
getName(temp);
|
getName(temp);
|
||||||
tlog0 << "Loaded AI named " << temp << std::endl;
|
tlog0 << "Loaded AI named " << temp << std::endl;
|
||||||
@ -59,3 +60,13 @@ CGlobalAI * CAIHandler::getNewAI(CCallback * cb, std::string dllname)
|
|||||||
ret->dllName = dllname;
|
ret->dllName = dllname;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CGlobalAI * CAIHandler::getNewAI(CCallback * cb, std::string dllname)
|
||||||
|
{
|
||||||
|
return createAnyAI<CGlobalAI>(cb, dllname, "GetNewAI");
|
||||||
|
}
|
||||||
|
|
||||||
|
CBattleGameInterface * CAIHandler::getNewBattleAI( CCallback * cb, std::string dllname )
|
||||||
|
{
|
||||||
|
return createAnyAI<CBattleGameInterface>(cb, dllname, "GetNewBattleAI");
|
||||||
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
using namespace boost::logic;
|
using namespace boost::logic;
|
||||||
class CCallback;
|
class CCallback;
|
||||||
|
class IBattleCallback;
|
||||||
class ICallback;
|
class ICallback;
|
||||||
class CGlobalAI;
|
class CGlobalAI;
|
||||||
struct Component;
|
struct Component;
|
||||||
@ -47,18 +48,46 @@ class CStackInstance;
|
|||||||
class CCreature;
|
class CCreature;
|
||||||
class CLoadFile;
|
class CLoadFile;
|
||||||
class CSaveFile;
|
class CSaveFile;
|
||||||
typedef TQuantity;
|
typedef si32 TQuantity;
|
||||||
template <typename Serializer> class CISer;
|
template <typename Serializer> class CISer;
|
||||||
template <typename Serializer> class COSer;
|
template <typename Serializer> class COSer;
|
||||||
|
|
||||||
class CGameInterface
|
class CBattleGameInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
bool human;
|
bool human;
|
||||||
int playerID;
|
int playerID;
|
||||||
std::string dllName;
|
std::string dllName;
|
||||||
|
|
||||||
virtual ~CGameInterface() {};
|
virtual ~CBattleGameInterface() {};
|
||||||
|
|
||||||
|
virtual void init(IBattleCallback * CB){};
|
||||||
|
|
||||||
|
//battle call-ins
|
||||||
|
virtual void actionFinished(const BattleAction *action){};//occurs AFTER every action taken by any stack or by the hero
|
||||||
|
virtual void actionStarted(const BattleAction *action){};//occurs BEFORE every action taken by any stack or by the hero
|
||||||
|
virtual BattleAction activeStack(int stackID)=0; //called when it's turn of that stack
|
||||||
|
virtual void battleAttack(const BattleAttack *ba){}; //called when stack is performing attack
|
||||||
|
virtual void battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa){}; //called when stack receives damage (after battleAttack())
|
||||||
|
virtual void battleEnd(const BattleResult *br){};
|
||||||
|
virtual void battleResultsApplied(){}; //called when all effects of last battle are applied
|
||||||
|
virtual void battleNewRoundFirst(int round){}; //called at the beginning of each turn before changes are applied;
|
||||||
|
virtual void battleNewRound(int round){}; //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
|
||||||
|
virtual void battleStackMoved(int ID, int dest, int distance, bool end){};
|
||||||
|
virtual void battleSpellCast(const BattleSpellCast *sc){};
|
||||||
|
virtual void battleStacksEffectsSet(const SetStackEffect & sse){};//called when a specific effect is set to stacks
|
||||||
|
virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side){}; //called by engine when battle starts; side=0 - left, side=1 - right
|
||||||
|
//virtual void battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles){}; //called when battlefield is prepared, prior the battle beginning
|
||||||
|
virtual void battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, si32 lifeDrainFrom){}; //called when stacks are healed / resurrected first element of pair - stack id, second - healed hp
|
||||||
|
virtual void battleNewStackAppeared(int stackID){}; //not called at the beginning of a battle or by resurrection; called eg. when elemental is summoned
|
||||||
|
virtual void battleObstaclesRemoved(const std::set<si32> & removedObstacles){}; //called when a certain set of obstacles is removed from batlefield; IDs of them are given
|
||||||
|
virtual void battleCatapultAttacked(const CatapultAttack & ca){}; //called when catapult makes an attack
|
||||||
|
virtual void battleStacksRemoved(const BattleStacksRemoved & bsr){}; //called when certain stack is completely removed from battlefield
|
||||||
|
};
|
||||||
|
|
||||||
|
class CGameInterface : public CBattleGameInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
virtual void buildChanged(const CGTownInstance *town, int buildingID, int what){}; //what: 1 - built, 2 - demolished
|
virtual void buildChanged(const CGTownInstance *town, int buildingID, int what){}; //what: 1 - built, 2 - demolished
|
||||||
|
|
||||||
//garrison operations
|
//garrison operations
|
||||||
@ -113,32 +142,13 @@ public:
|
|||||||
virtual void gameOver(ui8 player, bool victory){}; //player lost or won the game
|
virtual void gameOver(ui8 player, bool victory){}; //player lost or won the game
|
||||||
virtual void serialize(COSer<CSaveFile> &h, const int version){}; //saving
|
virtual void serialize(COSer<CSaveFile> &h, const int version){}; //saving
|
||||||
virtual void serialize(CISer<CLoadFile> &h, const int version){}; //loading
|
virtual void serialize(CISer<CLoadFile> &h, const int version){}; //loading
|
||||||
|
|
||||||
//battle call-ins
|
|
||||||
virtual void actionFinished(const BattleAction *action){};//occurs AFTER every action taken by any stack or by the hero
|
|
||||||
virtual void actionStarted(const BattleAction *action){};//occurs BEFORE every action taken by any stack or by the hero
|
|
||||||
virtual BattleAction activeStack(int stackID)=0; //called when it's turn of that stack
|
|
||||||
virtual void battleAttack(const BattleAttack *ba){}; //called when stack is performing attack
|
|
||||||
virtual void battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa){}; //called when stack receives damage (after battleAttack())
|
|
||||||
virtual void battleEnd(const BattleResult *br){};
|
|
||||||
virtual void battleResultsApplied(){}; //called when all effects of last battle are applied
|
|
||||||
virtual void battleNewRoundFirst(int round){}; //called at the beginning of each turn before changes are applied;
|
|
||||||
virtual void battleNewRound(int round){}; //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
|
|
||||||
virtual void battleStackMoved(int ID, int dest, int distance, bool end){};
|
|
||||||
virtual void battleSpellCast(const BattleSpellCast *sc){};
|
|
||||||
virtual void battleStacksEffectsSet(const SetStackEffect & sse){};//called when a specific effect is set to stacks
|
|
||||||
virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side){}; //called by engine when battle starts; side=0 - left, side=1 - right
|
|
||||||
//virtual void battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles){}; //called when battlefield is prepared, prior the battle beginning
|
|
||||||
virtual void battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, si32 lifeDrainFrom){}; //called when stacks are healed / resurrected first element of pair - stack id, second - healed hp
|
|
||||||
virtual void battleNewStackAppeared(int stackID){}; //not called at the beginning of a battle or by resurrection; called eg. when elemental is summoned
|
|
||||||
virtual void battleObstaclesRemoved(const std::set<si32> & removedObstacles){}; //called when a certain set of obstacles is removed from batlefield; IDs of them are given
|
|
||||||
virtual void battleCatapultAttacked(const CatapultAttack & ca){}; //called when catapult makes an attack
|
|
||||||
virtual void battleStacksRemoved(const BattleStacksRemoved & bsr){}; //called when certain stack is completely removed from battlefield
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CAIHandler
|
class CAIHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static CGlobalAI * getNewAI(CCallback * cb, std::string dllname);
|
static CGlobalAI * getNewAI(CCallback * cb, std::string dllname);
|
||||||
|
static CBattleGameInterface * getNewBattleAI(CCallback * cb, std::string dllname);
|
||||||
};
|
};
|
||||||
class CGlobalAI : public CGameInterface // AI class (to derivate)
|
class CGlobalAI : public CGameInterface // AI class (to derivate)
|
||||||
{
|
{
|
||||||
|
@ -52,7 +52,7 @@ struct PlayerSettings
|
|||||||
|
|
||||||
struct StartInfo
|
struct StartInfo
|
||||||
{
|
{
|
||||||
enum EMode {NEW_GAME, LOAD_GAME, CAMPAIGN, INVALID = 255};
|
enum EMode {NEW_GAME, LOAD_GAME, CAMPAIGN, DUEL, INVALID = 255};
|
||||||
|
|
||||||
ui8 mode; //uses EMode enum
|
ui8 mode; //uses EMode enum
|
||||||
ui8 difficulty; //0=easy; 4=impossible
|
ui8 difficulty; //0=easy; 4=impossible
|
||||||
|
34
StupidAI/StupidAI.cpp
Normal file
34
StupidAI/StupidAI.cpp
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#include "stdafx.h"
|
||||||
|
#include "StupidAI.h"
|
||||||
|
|
||||||
|
CStupidAI::CStupidAI(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CStupidAI::~CStupidAI(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStupidAI::init( IBattleCallback * CB )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStupidAI::actionFinished( const BattleAction *action )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStupidAI::actionStarted( const BattleAction *action )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
BattleAction CStupidAI::activeStack( int stackID )
|
||||||
|
{
|
||||||
|
BattleAction ba;
|
||||||
|
ba.DEFEND;
|
||||||
|
ba.stackNumber = stackID;
|
||||||
|
return ba;
|
||||||
|
}
|
14
StupidAI/StupidAI.h
Normal file
14
StupidAI/StupidAI.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
class CStupidAI : public CBattleGameInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CStupidAI(void);
|
||||||
|
~CStupidAI(void);
|
||||||
|
|
||||||
|
void init(IBattleCallback * CB) OVERRIDE;
|
||||||
|
void actionFinished(const BattleAction *action) OVERRIDE;//occurs AFTER every action taken by any stack or by the hero
|
||||||
|
void actionStarted(const BattleAction *action) OVERRIDE;//occurs BEFORE every action taken by any stack or by the hero
|
||||||
|
BattleAction activeStack(int stackID) OVERRIDE; //called when it's turn of that stack
|
||||||
|
};
|
||||||
|
|
87
StupidAI/StupidAI.vcxproj
Normal file
87
StupidAI/StupidAI.vcxproj
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{15DABC90-234A-4B6B-9EEB-777C4768B82B}</ProjectGuid>
|
||||||
|
<RootNamespace>StupidAI</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>MultiByte</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup />
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<AdditionalIncludeDirectories>E:\C++\Lua_includes;E:\vcmi\rep - assembla\trunk\lua src;E:\C++\boost_1_43_0;E:\C++\SDL_mixer-1.2.7\include;E:\C++\SDL_ttf-2.0.8\include;E:\C++\zlib 1.2.3 binaries\include;E:\C++\SDL-1.2.11\devlibs - visual\SDL-1.2.11\include;E:\C++\SDL_Image 1.2.5\SDL_image-1.2.5\include;%(AdditionalIncludeDirectories)options></AdditionalIncludeDirectories>
|
||||||
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
|
<PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<AdditionalDependencies>VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<AdditionalLibraryDirectories>E:\vcmi\rep - assembla\trunk;E:\C++\lua bin;E:\C++\boost_1_43_0\lib;E:\C++\SDL_mixer-1.2.7\lib;E:\C++\SDL_ttf-2.0.8\lib;E:\C++\zlib 1.2.3 binaries\lib;E:\C++\SDL-1.2.11\devlibs - visual\SDL-1.2.11\lib;E:\C++\SDL_Image 1.2.5\SDL_image-1.2.5\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<AdditionalIncludeDirectories>E:\C++\Lua_includes;E:\vcmi\rep - assembla\trunk\lua src;E:\C++\boost_1_43_0;E:\C++\SDL_mixer-1.2.7\include;E:\C++\SDL_ttf-2.0.8\include;E:\C++\zlib 1.2.3 binaries\include;E:\C++\SDL-1.2.11\devlibs - visual\SDL-1.2.11\include;E:\C++\SDL_Image 1.2.5\SDL_image-1.2.5\include;%(AdditionalIncludeDirectories)options></AdditionalIncludeDirectories>
|
||||||
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
|
<PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<AdditionalDependencies>VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
<AdditionalLibraryDirectories>E:\vcmi\rep - assembla\trunk;E:\C++\lua bin;E:\C++\boost_1_43_0\lib;E:\C++\SDL_mixer-1.2.7\lib;E:\C++\SDL_ttf-2.0.8\lib;E:\C++\zlib 1.2.3 binaries\lib;E:\C++\SDL-1.2.11\devlibs - visual\SDL-1.2.11\lib;E:\C++\SDL_Image 1.2.5\SDL_image-1.2.5\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="main.cpp" />
|
||||||
|
<ClCompile Include="stdafx.cpp">
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||||
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="StupidAI.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="stdafx.h" />
|
||||||
|
<ClInclude Include="StupidAI.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
30
StupidAI/main.cpp
Normal file
30
StupidAI/main.cpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#include "stdafx.h"
|
||||||
|
#include "StupidAI.h"
|
||||||
|
|
||||||
|
const char *g_cszAiName = "Stupid AI 0.1";
|
||||||
|
|
||||||
|
extern "C" DLL_F_EXPORT int GetGlobalAiVersion()
|
||||||
|
{
|
||||||
|
return AI_INTERFACE_VER;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" DLL_F_EXPORT void GetAiName(char* name)
|
||||||
|
{
|
||||||
|
strcpy_s(name, strlen(g_cszAiName) + 1, g_cszAiName);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" DLL_F_EXPORT char* GetAiNameS()
|
||||||
|
{
|
||||||
|
// need to be defined
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" DLL_F_EXPORT CBattleGameInterface* GetNewBattleAI()
|
||||||
|
{
|
||||||
|
return new CStupidAI();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" DLL_F_EXPORT void ReleaseBattleAI(CBattleGameInterface* i)
|
||||||
|
{
|
||||||
|
delete (CStupidAI*)i;
|
||||||
|
}
|
1
StupidAI/stdafx.cpp
Normal file
1
StupidAI/stdafx.cpp
Normal file
@ -0,0 +1 @@
|
|||||||
|
#include "stdafx.h"
|
2
StupidAI/stdafx.h
Normal file
2
StupidAI/stdafx.h
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../../AI_Base.h"
|
@ -43,6 +43,7 @@
|
|||||||
#include "../lib/NetPacks.h"
|
#include "../lib/NetPacks.h"
|
||||||
#include "CMessage.h"
|
#include "CMessage.h"
|
||||||
#include "../lib/CObjectHandler.h"
|
#include "../lib/CObjectHandler.h"
|
||||||
|
#include <boost/program_options.hpp>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include "SDL_syswm.h"
|
#include "SDL_syswm.h"
|
||||||
@ -54,6 +55,8 @@
|
|||||||
#undef main
|
#undef main
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
namespace po = boost::program_options;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CMT.cpp, part of VCMI engine
|
* CMT.cpp, part of VCMI engine
|
||||||
*
|
*
|
||||||
@ -89,6 +92,7 @@ void dispose();
|
|||||||
void playIntro();
|
void playIntro();
|
||||||
static void listenForEvents();
|
static void listenForEvents();
|
||||||
void requestChangingResolution();
|
void requestChangingResolution();
|
||||||
|
void startGame(StartInfo * options, CConnection *serv = NULL);
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#ifndef _GNU_SOURCE
|
#ifndef _GNU_SOURCE
|
||||||
@ -160,7 +164,6 @@ void init()
|
|||||||
//tlog0<<"Initialization CPreGame (together): "<<tmh.getDif()<<std::endl;
|
//tlog0<<"Initialization CPreGame (together): "<<tmh.getDif()<<std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
static void prog_version(void)
|
static void prog_version(void)
|
||||||
{
|
{
|
||||||
printf("%s\n", NAME_VER);
|
printf("%s\n", NAME_VER);
|
||||||
@ -180,7 +183,6 @@ static void prog_help(const char *progname)
|
|||||||
printf(" -h, --help display this help and exit\n");
|
printf(" -h, --help display this help and exit\n");
|
||||||
printf(" -v, --version display version information and exit\n");
|
printf(" -v, --version display version information and exit\n");
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -189,50 +191,42 @@ int _tmain(int argc, _TCHAR* argv[])
|
|||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
tlog0 << "Starting... " << std::endl;
|
||||||
|
po::options_description opts("Allowed options");
|
||||||
|
opts.add_options()
|
||||||
|
("help,h", "display help and exit")
|
||||||
|
("version,v", "display version information and exit")
|
||||||
|
("battle,b", "runs game in duel mode (battle-only");
|
||||||
|
|
||||||
#ifndef _WIN32
|
po::variables_map vm;
|
||||||
struct option long_options[] = {
|
if(argc > 1)
|
||||||
{ "help", 0, NULL, 'h' },
|
{
|
||||||
{ "version", 0, NULL, 'v' },
|
try
|
||||||
{ NULL, 0, NULL, 0 }
|
{
|
||||||
};
|
po::store(po::parse_command_line(argc, argv, opts), vm);
|
||||||
|
}
|
||||||
|
catch(std::exception &e)
|
||||||
|
{
|
||||||
|
tlog1 << "Failure during parsing command-line options:\n" << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while(1) {
|
po::notify(vm);
|
||||||
int c;
|
if(vm.count("help"))
|
||||||
int option_index;
|
{
|
||||||
|
prog_help(0);
|
||||||
c = getopt_long (argc, argv, "hv",
|
|
||||||
long_options, &option_index);
|
|
||||||
|
|
||||||
if (c == EOF)
|
|
||||||
break;
|
|
||||||
else if (c == '?')
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
switch(c) {
|
|
||||||
case 'h':
|
|
||||||
prog_help(argv[0]);
|
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
}
|
||||||
|
if(vm.count("version"))
|
||||||
case 'v':
|
{
|
||||||
prog_version();
|
prog_version();
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (optind < argc) {
|
|
||||||
printf ("Extra arguments: %s\n", argv[optind++]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//Set environment vars to make window centered. Sometimes work, sometimes not. :/
|
//Set environment vars to make window centered. Sometimes work, sometimes not. :/
|
||||||
putenv("SDL_VIDEO_WINDOW_POS");
|
putenv("SDL_VIDEO_WINDOW_POS");
|
||||||
putenv("SDL_VIDEO_CENTERED=1");
|
putenv("SDL_VIDEO_CENTERED=1");
|
||||||
|
|
||||||
tlog0 << "Starting... " << std::endl;
|
|
||||||
timeHandler total, pomtime;
|
timeHandler total, pomtime;
|
||||||
std::cout.flags(std::ios::unitbuf);
|
std::cout.flags(std::ios::unitbuf);
|
||||||
logfile = new std::ofstream("VCMI_Client_log.txt");
|
logfile = new std::ofstream("VCMI_Client_log.txt");
|
||||||
@ -267,15 +261,26 @@ int main(int argc, char** argv)
|
|||||||
|
|
||||||
//we can properly play intro only in the main thread, so we have to move loading to the separate thread
|
//we can properly play intro only in the main thread, so we have to move loading to the separate thread
|
||||||
boost::thread loading(init);
|
boost::thread loading(init);
|
||||||
|
|
||||||
|
if(!vm.count("battle"))
|
||||||
playIntro();
|
playIntro();
|
||||||
|
|
||||||
SDL_FillRect(screen,NULL,0);
|
SDL_FillRect(screen,NULL,0);
|
||||||
SDL_Flip(screen);
|
SDL_Flip(screen);
|
||||||
loading.join();
|
loading.join();
|
||||||
tlog0<<"Initialization of VCMI (together): "<<total.getDif()<<std::endl;
|
tlog0<<"Initialization of VCMI (together): "<<total.getDif()<<std::endl;
|
||||||
|
|
||||||
|
if(!vm.count("battle"))
|
||||||
|
{
|
||||||
CCS->musich->playMusic(musicBase::mainMenu, -1);
|
CCS->musich->playMusic(musicBase::mainMenu, -1);
|
||||||
|
|
||||||
GH.curInt = new CGPreGame; //will set CGP pointer to itself
|
GH.curInt = new CGPreGame; //will set CGP pointer to itself
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
StartInfo *si = new StartInfo();
|
||||||
|
si->mode = StartInfo::DUEL;
|
||||||
|
startGame(si);
|
||||||
|
}
|
||||||
mainGUIThread = new boost::thread(&CGuiHandler::run, boost::ref(GH));
|
mainGUIThread = new boost::thread(&CGuiHandler::run, boost::ref(GH));
|
||||||
listenForEvents();
|
listenForEvents();
|
||||||
|
|
||||||
@ -667,6 +672,7 @@ void startGame(StartInfo * options, CConnection *serv/* = NULL*/)
|
|||||||
{
|
{
|
||||||
case StartInfo::NEW_GAME:
|
case StartInfo::NEW_GAME:
|
||||||
case StartInfo::CAMPAIGN:
|
case StartInfo::CAMPAIGN:
|
||||||
|
case StartInfo::DUEL:
|
||||||
client->newGame(serv, options);
|
client->newGame(serv, options);
|
||||||
break;
|
break;
|
||||||
case StartInfo::LOAD_GAME:
|
case StartInfo::LOAD_GAME:
|
||||||
|
@ -367,24 +367,30 @@ void CClient::newGame( CConnection *con, StartInfo *si )
|
|||||||
gs = const_cast<CGameInfo*>(CGI)->state;
|
gs = const_cast<CGameInfo*>(CGI)->state;
|
||||||
gs->scenarioOps = si;
|
gs->scenarioOps = si;
|
||||||
gs->init(si, sum, seed);
|
gs->init(si, sum, seed);
|
||||||
|
|
||||||
const_cast<CGameInfo*>(CGI)->mh = new CMapHandler();
|
|
||||||
tlog0 <<"Initializing GameState (together): "<<tmh.getDif()<<std::endl;
|
tlog0 <<"Initializing GameState (together): "<<tmh.getDif()<<std::endl;
|
||||||
|
|
||||||
|
if(!gs->map)
|
||||||
|
{
|
||||||
|
const_cast<CGameInfo*>(CGI)->mh = new CMapHandler();
|
||||||
CGI->mh->map = gs->map;
|
CGI->mh->map = gs->map;
|
||||||
tlog0 <<"Creating mapHandler: "<<tmh.getDif()<<std::endl;
|
tlog0 <<"Creating mapHandler: "<<tmh.getDif()<<std::endl;
|
||||||
CGI->mh->init();
|
CGI->mh->init();
|
||||||
initVillagesCapitols(gs->map);
|
initVillagesCapitols(gs->map);
|
||||||
pathInfo = new CPathsInfo(int3(gs->map->width, gs->map->height, gs->map->twoLevel+1));
|
pathInfo = new CPathsInfo(int3(gs->map->width, gs->map->height, gs->map->twoLevel+1));
|
||||||
tlog0 <<"Initializing mapHandler (together): "<<tmh.getDif()<<std::endl;
|
tlog0 <<"Initializing mapHandler (together): "<<tmh.getDif()<<std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
int humanPlayers = 0;
|
int humanPlayers = 0;
|
||||||
for(std::map<int, PlayerSettings>::iterator it = gs->scenarioOps->playerInfos.begin();
|
for(std::map<int, PlayerSettings>::iterator it = gs->scenarioOps->playerInfos.begin();
|
||||||
it != gs->scenarioOps->playerInfos.end(); ++it)//initializing interfaces for players
|
it != gs->scenarioOps->playerInfos.end(); ++it)//initializing interfaces for players
|
||||||
{
|
{
|
||||||
ui8 color = it->first;
|
ui8 color = it->first;
|
||||||
|
gs->currentPlayer = color;
|
||||||
if(!vstd::contains(myPlayers, color))
|
if(!vstd::contains(myPlayers, color))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if(si->mode != StartInfo::DUEL)
|
||||||
|
{
|
||||||
CCallback *cb = new CCallback(gs,color,this);
|
CCallback *cb = new CCallback(gs,color,this);
|
||||||
if(!it->second.human)
|
if(!it->second.human)
|
||||||
{
|
{
|
||||||
@ -395,9 +401,19 @@ void CClient::newGame( CConnection *con, StartInfo *si )
|
|||||||
playerint[color] = new CPlayerInterface(color);
|
playerint[color] = new CPlayerInterface(color);
|
||||||
humanPlayers++;
|
humanPlayers++;
|
||||||
}
|
}
|
||||||
gs->currentPlayer = color;
|
|
||||||
playerint[color]->init(cb);
|
playerint[color]->init(cb);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CBattleCallback * cbc = new CBattleCallback(gs, color, this);
|
||||||
|
battleints[color] = CAIHandler::getNewBattleAI(cb,conf.cc.defaultAI);
|
||||||
|
battleints[color]->init(cbc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
playerint[254] = new CPlayerInterface(-1);
|
||||||
|
playerint[254]->init(new CCallback(gs, -1, this));
|
||||||
|
|
||||||
serv->addStdVecItems(const_cast<CGameInfo*>(CGI)->state);
|
serv->addStdVecItems(const_cast<CGameInfo*>(CGI)->state);
|
||||||
hotSeat = (humanPlayers > 1);
|
hotSeat = (humanPlayers > 1);
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
class CBattleGameInterface;
|
||||||
struct StartInfo;
|
struct StartInfo;
|
||||||
class CGameState;
|
class CGameState;
|
||||||
class CGameInterface;
|
class CGameInterface;
|
||||||
@ -61,6 +62,7 @@ public:
|
|||||||
CCallback *cb;
|
CCallback *cb;
|
||||||
std::set<CCallback*> callbacks; //callbacks given to player interfaces
|
std::set<CCallback*> callbacks; //callbacks given to player interfaces
|
||||||
std::map<ui8,CGameInterface *> playerint;
|
std::map<ui8,CGameInterface *> playerint;
|
||||||
|
std::map<ui8,CBattleGameInterface *> battleints;
|
||||||
bool hotSeat;
|
bool hotSeat;
|
||||||
CConnection *serv;
|
CConnection *serv;
|
||||||
BattleAction *curbaction;
|
BattleAction *curbaction;
|
||||||
|
1
global.h
1
global.h
@ -41,6 +41,7 @@ extern std::string NAME_AFFIX; //client / server
|
|||||||
#define DATA_DIR "."
|
#define DATA_DIR "."
|
||||||
#define USER_DIR "."
|
#define USER_DIR "."
|
||||||
#define BIN_DIR "."
|
#define BIN_DIR "."
|
||||||
|
#define LIB_DIR "AI"
|
||||||
#define SERVER_NAME "VCMI_server.exe"
|
#define SERVER_NAME "VCMI_server.exe"
|
||||||
#else
|
#else
|
||||||
#ifndef DATA_DIR
|
#ifndef DATA_DIR
|
||||||
|
@ -1456,6 +1456,364 @@ CGameState::~CGameState()
|
|||||||
capitols.clear();
|
capitols.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace CGH
|
||||||
|
{
|
||||||
|
using namespace std;
|
||||||
|
static void readItTo(ifstream & input, vector< vector<int> > & dest) //reads 7 lines, i-th one containing i integers, and puts it to 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BattleInfo * setupBattle( int3 tile, int terrain, int terType, const CArmedInstance *armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance *town )
|
||||||
|
{
|
||||||
|
CMP_stack cmpst;
|
||||||
|
BattleInfo *curB = new BattleInfo;
|
||||||
|
curB->side1 = armies[0]->tempOwner;
|
||||||
|
curB->side2 = armies[1]->tempOwner;
|
||||||
|
if(curB->side2 == 254)
|
||||||
|
curB->side2 = 255;
|
||||||
|
|
||||||
|
std::vector<CStack*> & stacks = (curB->stacks);
|
||||||
|
|
||||||
|
curB->tile = tile;
|
||||||
|
curB->belligerents[0] = const_cast<CArmedInstance*>(armies[0]);
|
||||||
|
curB->belligerents[1] = const_cast<CArmedInstance*>(armies[1]);
|
||||||
|
curB->heroes[0] = const_cast<CGHeroInstance*>(heroes[0]);
|
||||||
|
curB->heroes[1] = const_cast<CGHeroInstance*>(heroes[1]);
|
||||||
|
curB->round = -2;
|
||||||
|
curB->activeStack = -1;
|
||||||
|
|
||||||
|
if(town)
|
||||||
|
{
|
||||||
|
curB->tid = town->id;
|
||||||
|
curB->siege = town->fortLevel();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
curB->tid = -1;
|
||||||
|
curB->siege = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//reading battleStartpos
|
||||||
|
std::ifstream positions;
|
||||||
|
positions.open(DATA_DIR "/config/battleStartpos.txt", std::ios_base::in|std::ios_base::binary);
|
||||||
|
if(!positions.is_open())
|
||||||
|
{
|
||||||
|
tlog1<<"Unable to open battleStartpos.txt!"<<std::endl;
|
||||||
|
}
|
||||||
|
std::string dump;
|
||||||
|
positions>>dump; positions>>dump;
|
||||||
|
std::vector< std::vector<int> > attackerLoose, defenderLoose, attackerTight, defenderTight, attackerCreBank, defenderCreBank;
|
||||||
|
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>>dump;
|
||||||
|
positions>>dump;
|
||||||
|
CGH::readItTo(positions, attackerCreBank);
|
||||||
|
positions>>dump;
|
||||||
|
CGH::readItTo(positions, defenderCreBank);
|
||||||
|
positions.close();
|
||||||
|
//battleStartpos read
|
||||||
|
|
||||||
|
int k = 0; //stack serial
|
||||||
|
for(TSlots::const_iterator i = armies[0]->Slots().begin(); i!=armies[0]->Slots().end(); i++, k++)
|
||||||
|
{
|
||||||
|
int pos;
|
||||||
|
if(creatureBank)
|
||||||
|
pos = attackerCreBank[armies[0]->stacksCount()-1][k];
|
||||||
|
else if(armies[0]->formation)
|
||||||
|
pos = attackerTight[armies[0]->stacksCount()-1][k];
|
||||||
|
else
|
||||||
|
pos = attackerLoose[armies[0]->stacksCount()-1][k];
|
||||||
|
|
||||||
|
CStack * stack = curB->generateNewStack(*i->second, stacks.size(), true, i->first, pos);
|
||||||
|
stacks.push_back(stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
k = 0;
|
||||||
|
for(TSlots::const_iterator i = armies[1]->Slots().begin(); i!=armies[1]->Slots().end(); i++, k++)
|
||||||
|
{
|
||||||
|
int pos;
|
||||||
|
if(creatureBank)
|
||||||
|
pos = defenderCreBank[armies[1]->stacksCount()-1][k];
|
||||||
|
else if(armies[1]->formation)
|
||||||
|
pos = defenderTight[armies[1]->stacksCount()-1][k];
|
||||||
|
else
|
||||||
|
pos = defenderLoose[armies[1]->stacksCount()-1][k];
|
||||||
|
|
||||||
|
CStack * stack = curB->generateNewStack(*i->second, stacks.size(), false, i->first, pos);
|
||||||
|
stacks.push_back(stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(unsigned g=0; g<stacks.size(); ++g) //shifting positions of two-hex creatures
|
||||||
|
{
|
||||||
|
if((stacks[g]->position%17)==1 && stacks[g]->doubleWide() && stacks[g]->attackerOwned)
|
||||||
|
{
|
||||||
|
stacks[g]->position += 1;
|
||||||
|
}
|
||||||
|
else if((stacks[g]->position%17)==15 && stacks[g]->doubleWide() && !stacks[g]->attackerOwned)
|
||||||
|
{
|
||||||
|
stacks[g]->position -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//adding war machines
|
||||||
|
if(heroes[0])
|
||||||
|
{
|
||||||
|
if(heroes[0]->getArt(13)) //ballista
|
||||||
|
{
|
||||||
|
CStack * stack = curB->generateNewStack(CStackBasicDescriptor(146, 1), stacks.size(), true, 255, 52);
|
||||||
|
stacks.push_back(stack);
|
||||||
|
}
|
||||||
|
if(heroes[0]->getArt(14)) //ammo cart
|
||||||
|
{
|
||||||
|
CStack * stack = curB->generateNewStack(CStackBasicDescriptor(148, 1), stacks.size(), true, 255, 18);
|
||||||
|
stacks.push_back(stack);
|
||||||
|
}
|
||||||
|
if(heroes[0]->getArt(15)) //first aid tent
|
||||||
|
{
|
||||||
|
CStack * stack = curB->generateNewStack(CStackBasicDescriptor(147, 1), stacks.size(), true, 255, 154);
|
||||||
|
stacks.push_back(stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(heroes[1])
|
||||||
|
{
|
||||||
|
//defending hero shouldn't receive ballista (bug #551)
|
||||||
|
if(heroes[1]->getArt(13) && !town) //ballista
|
||||||
|
{
|
||||||
|
CStack * stack = curB->generateNewStack(CStackBasicDescriptor(146, 1), stacks.size(), false, 255, 66);
|
||||||
|
stacks.push_back(stack);
|
||||||
|
}
|
||||||
|
if(heroes[1]->getArt(14)) //ammo cart
|
||||||
|
{
|
||||||
|
CStack * stack = curB->generateNewStack(CStackBasicDescriptor(148, 1), stacks.size(), false, 255, 32);
|
||||||
|
stacks.push_back(stack);
|
||||||
|
}
|
||||||
|
if(heroes[1]->getArt(15)) //first aid tent
|
||||||
|
{
|
||||||
|
CStack * stack = curB->generateNewStack(CStackBasicDescriptor(147, 1), stacks.size(), false, 255, 168);
|
||||||
|
stacks.push_back(stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(town && heroes[0] && town->hasFort()) //catapult
|
||||||
|
{
|
||||||
|
CStack * stack = curB->generateNewStack(CStackBasicDescriptor(145, 1), stacks.size(), true, 255, 120);
|
||||||
|
stacks.push_back(stack);
|
||||||
|
}
|
||||||
|
//war machines added
|
||||||
|
|
||||||
|
switch(curB->siege) //adding towers
|
||||||
|
{
|
||||||
|
|
||||||
|
case 3: //castle
|
||||||
|
{//lower tower / upper tower
|
||||||
|
CStack * stack = curB->generateNewStack(CStackBasicDescriptor(149, 1), stacks.size(), false, 255, -4);
|
||||||
|
stacks.push_back(stack);
|
||||||
|
stack = curB->generateNewStack(CStackBasicDescriptor(149, 1), stacks.size(), false, 255, -3);
|
||||||
|
stacks.push_back(stack);
|
||||||
|
}
|
||||||
|
case 2: //citadel
|
||||||
|
{//main tower
|
||||||
|
CStack * stack = curB->generateNewStack(CStackBasicDescriptor(149, 1), stacks.size(), false, 255, -2);
|
||||||
|
stacks.push_back(stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stable_sort(stacks.begin(),stacks.end(),cmpst);
|
||||||
|
|
||||||
|
//seting up siege
|
||||||
|
if(town && town->hasFort())
|
||||||
|
{
|
||||||
|
for(int b=0; b<ARRAY_COUNT(curB->si.wallState); ++b)
|
||||||
|
{
|
||||||
|
curB->si.wallState[b] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//randomize obstacles
|
||||||
|
if(town == NULL && !creatureBank) //do it only when it's not siege and not creature bank
|
||||||
|
{
|
||||||
|
bool obAv[BFIELD_SIZE]; //availability of hexes for obstacles;
|
||||||
|
std::vector<int> possibleObstacles;
|
||||||
|
|
||||||
|
for(int i=0; i<BFIELD_SIZE; ++i)
|
||||||
|
{
|
||||||
|
if(i%17 < 4 || i%17 > 12)
|
||||||
|
{
|
||||||
|
obAv[i] = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
obAv[i] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(std::map<int, CObstacleInfo>::const_iterator g=VLC->heroh->obstacles.begin(); g!=VLC->heroh->obstacles.end(); ++g)
|
||||||
|
{
|
||||||
|
if(g->second.allowedTerrains[terType-1] == '1') //we need to take terType with -1 because terrain ids start from 1 and allowedTerrains array is indexed from 0
|
||||||
|
{
|
||||||
|
possibleObstacles.push_back(g->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
srand(time(NULL));
|
||||||
|
if(possibleObstacles.size() > 0) //we cannot place any obstacles when we don't have them
|
||||||
|
{
|
||||||
|
int toBlock = rand()%6 + 6; //how many hexes should be blocked by obstacles
|
||||||
|
while(toBlock>0)
|
||||||
|
{
|
||||||
|
CObstacleInstance coi;
|
||||||
|
coi.uniqueID = curB->obstacles.size();
|
||||||
|
coi.ID = possibleObstacles[rand()%possibleObstacles.size()];
|
||||||
|
coi.pos = rand()%BFIELD_SIZE;
|
||||||
|
std::vector<int> block = VLC->heroh->obstacles[coi.ID].getBlocked(coi.pos);
|
||||||
|
bool badObstacle = false;
|
||||||
|
for(int b=0; b<block.size(); ++b)
|
||||||
|
{
|
||||||
|
if(block[b] < 0 || block[b] >= BFIELD_SIZE || !obAv[block[b]])
|
||||||
|
{
|
||||||
|
badObstacle = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(badObstacle) continue;
|
||||||
|
//obstacle can be placed
|
||||||
|
curB->obstacles.push_back(coi);
|
||||||
|
for(int b=0; b<block.size(); ++b)
|
||||||
|
{
|
||||||
|
if(block[b] >= 0 && block[b] < BFIELD_SIZE)
|
||||||
|
obAv[block[b]] = false;
|
||||||
|
}
|
||||||
|
toBlock -= block.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// //giving building bonuses, if siege and we have harrisoned hero
|
||||||
|
// if (town)
|
||||||
|
// {
|
||||||
|
// if (heroes[1])
|
||||||
|
// {
|
||||||
|
// for (int i=0; i<4; i++)
|
||||||
|
// {
|
||||||
|
// int val = town->defenceBonus(i);
|
||||||
|
// if (val)
|
||||||
|
// {
|
||||||
|
// GiveBonus gs;
|
||||||
|
// gs.bonus = Bonus(Bonus::ONE_BATTLE, Bonus::PRIMARY_SKILL, Bonus::OBJECT, val, -1, "", i);
|
||||||
|
// gs.id = heroes[1]->id;
|
||||||
|
// sendAndApply(&gs);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else//if we don't have hero - apply separately, if hero present - will be taken from hero bonuses
|
||||||
|
// {
|
||||||
|
// if(town->subID == 0 && vstd::contains(town->builtBuildings,22)) //castle, brotherhood of sword built
|
||||||
|
// for(int g=0; g<stacks.size(); ++g)
|
||||||
|
// stacks[g]->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, 2, Bonus::TOWN_STRUCTURE));
|
||||||
|
//
|
||||||
|
// else if(vstd::contains(town->builtBuildings,5)) //tavern is built
|
||||||
|
// for(int g=0; g<stacks.size(); ++g)
|
||||||
|
// stacks[g]->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, 1, Bonus::TOWN_STRUCTURE));
|
||||||
|
//
|
||||||
|
// if(town->subID == 1 && vstd::contains(town->builtBuildings,21)) //rampart, fountain of fortune is present
|
||||||
|
// for(int g=0; g<stacks.size(); ++g)
|
||||||
|
// stacks[g]->addNewBonus(makeFeature(Bonus::LUCK, Bonus::ONE_BATTLE, 0, 2, Bonus::TOWN_STRUCTURE));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
//giving terrain overalay premies
|
||||||
|
int bonusSubtype = -1;
|
||||||
|
switch(terType)
|
||||||
|
{
|
||||||
|
case 9: //magic plains
|
||||||
|
{
|
||||||
|
bonusSubtype = 0;
|
||||||
|
}
|
||||||
|
case 14: //fiery fields
|
||||||
|
{
|
||||||
|
if(bonusSubtype == -1) bonusSubtype = 1;
|
||||||
|
}
|
||||||
|
case 15: //rock lands
|
||||||
|
{
|
||||||
|
if(bonusSubtype == -1) bonusSubtype = 8;
|
||||||
|
}
|
||||||
|
case 16: //magic clouds
|
||||||
|
{
|
||||||
|
if(bonusSubtype == -1) bonusSubtype = 2;
|
||||||
|
}
|
||||||
|
case 17: //lucid pools
|
||||||
|
{
|
||||||
|
if(bonusSubtype == -1) bonusSubtype = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
{ //common part for cases 9, 14, 15, 16, 17
|
||||||
|
curB->addNewBonus(new Bonus(Bonus::ONE_BATTLE, Bonus::MAGIC_SCHOOL_SKILL, Bonus::TERRAIN_OVERLAY, 3, -1, "", bonusSubtype));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 18: //holy ground
|
||||||
|
{
|
||||||
|
curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, +1, Bonus::TERRAIN_OVERLAY)->addLimiter(new CreatureAlignmentLimiter(GOOD)));
|
||||||
|
curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, -1, Bonus::TERRAIN_OVERLAY)->addLimiter(new CreatureAlignmentLimiter(EVIL)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 19: //clover field
|
||||||
|
{ //+2 luck bonus for neutral creatures
|
||||||
|
curB->addNewBonus(makeFeature(Bonus::LUCK, Bonus::ONE_BATTLE, 0, +2, Bonus::TERRAIN_OVERLAY)->addLimiter(new CreatureFactionLimiter(-1)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 20: //evil fog
|
||||||
|
{
|
||||||
|
curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, -1, Bonus::TERRAIN_OVERLAY)->addLimiter(new CreatureAlignmentLimiter(GOOD)));
|
||||||
|
curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, +1, Bonus::TERRAIN_OVERLAY)->addLimiter(new CreatureAlignmentLimiter(EVIL)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 22: //cursed ground
|
||||||
|
{
|
||||||
|
curB->addNewBonus(makeFeature(Bonus::NO_MORALE, Bonus::ONE_BATTLE, 0, 0, Bonus::TERRAIN_OVERLAY));
|
||||||
|
curB->addNewBonus(makeFeature(Bonus::NO_LUCK, Bonus::ONE_BATTLE, 0, 0, Bonus::TERRAIN_OVERLAY));
|
||||||
|
curB->addNewBonus(makeFeature(Bonus::BLOCK_SPELLS_ABOVE_LEVEL, Bonus::ONE_BATTLE, 0, 1, Bonus::TERRAIN_OVERLAY));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//overlay premies given
|
||||||
|
|
||||||
|
//native terrain bonuses
|
||||||
|
if(town) //during siege always take premies for native terrain of faction
|
||||||
|
terrain = VLC->heroh->nativeTerrains[town->town->typeID];
|
||||||
|
|
||||||
|
ILimiter *nativeTerrain = new CreatureNativeTerrainLimiter(terrain);
|
||||||
|
curB->addNewBonus(makeFeature(Bonus::STACKS_SPEED, Bonus::ONE_BATTLE, 0, 1, Bonus::TERRAIN_NATIVE)->addLimiter(nativeTerrain));
|
||||||
|
curB->addNewBonus(makeFeature(Bonus::PRIMARY_SKILL, Bonus::ONE_BATTLE, PrimarySkill::ATTACK, 1, Bonus::TERRAIN_NATIVE)->addLimiter(nativeTerrain));
|
||||||
|
curB->addNewBonus(makeFeature(Bonus::PRIMARY_SKILL, Bonus::ONE_BATTLE, PrimarySkill::DEFENSE, 1, Bonus::TERRAIN_NATIVE)->addLimiter(nativeTerrain));
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
return curB;
|
||||||
|
}
|
||||||
|
|
||||||
|
BattleInfo * CGameState::setupBattle(int3 tile, const CArmedInstance *armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance *town)
|
||||||
|
{
|
||||||
|
int terrain = map->getTile(tile).tertype;
|
||||||
|
int terType = battleGetBattlefieldType(tile);
|
||||||
|
return ::setupBattle(tile, terrain, terType, armies, heroes, creatureBank, town);
|
||||||
|
}
|
||||||
|
|
||||||
void CGameState::init( StartInfo * si, ui32 checksum, int Seed )
|
void CGameState::init( StartInfo * si, ui32 checksum, int Seed )
|
||||||
{
|
{
|
||||||
struct HLP
|
struct HLP
|
||||||
@ -1563,6 +1921,35 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed )
|
|||||||
map->initFromBytes((const unsigned char*)mapContent.c_str());
|
map->initFromBytes((const unsigned char*)mapContent.c_str());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case StartInfo::DUEL:
|
||||||
|
{
|
||||||
|
int3 tile;
|
||||||
|
int terType = TerrainTile::grass;
|
||||||
|
int terrain = 15;
|
||||||
|
const CArmedInstance *armies[2];
|
||||||
|
const CGHeroInstance *heroes[2];
|
||||||
|
const CGTownInstance *town = NULL;
|
||||||
|
CGHeroInstance *h = new CGHeroInstance();
|
||||||
|
h->subID = 1;
|
||||||
|
h->initHero(1);
|
||||||
|
h->initObj();
|
||||||
|
//h->putStack(0, new CStackInstance(34, 5));
|
||||||
|
|
||||||
|
CGCreature *c = new CGCreature();
|
||||||
|
c->putStack(0, new CStackInstance(70, 6));
|
||||||
|
c->subID = 34;
|
||||||
|
c->initObj();
|
||||||
|
|
||||||
|
heroes[0] = h;
|
||||||
|
heroes[1] = NULL;
|
||||||
|
|
||||||
|
armies[0] = h;
|
||||||
|
armies[1] = c;
|
||||||
|
|
||||||
|
curB = ::setupBattle(tile, terrain, terType, armies, heroes, false, town);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
tlog1 << "Wrong mode: " << (int)scenarioOps->mode << std::endl;
|
tlog1 << "Wrong mode: " << (int)scenarioOps->mode << std::endl;
|
||||||
return;
|
return;
|
||||||
|
@ -171,7 +171,7 @@ public:
|
|||||||
|
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
h & players & fogOfWarMap;
|
h & id & players & fogOfWarMap;
|
||||||
h & static_cast<CBonusSystemNode&>(*this);
|
h & static_cast<CBonusSystemNode&>(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -498,6 +498,8 @@ public:
|
|||||||
bool checkForStandardLoss(ui8 player) const; //checks if given player lost the game
|
bool checkForStandardLoss(ui8 player) const; //checks if given player lost the game
|
||||||
void obtainPlayersStats(SThievesGuildInfo & tgi, int level); //fills tgi with info about other players that is available at given level of thieves' guild
|
void obtainPlayersStats(SThievesGuildInfo & tgi, int level); //fills tgi with info about other players that is available at given level of thieves' guild
|
||||||
bmap<ui32, ConstTransitivePtr<CGHeroInstance> > unusedHeroesFromPool(); //heroes pool without heroes that are available in taverns
|
bmap<ui32, ConstTransitivePtr<CGHeroInstance> > unusedHeroesFromPool(); //heroes pool without heroes that are available in taverns
|
||||||
|
BattleInfo * setupBattle(int3 tile, const CArmedInstance *armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance *town);
|
||||||
|
|
||||||
|
|
||||||
bool isVisible(int3 pos, int player);
|
bool isVisible(int3 pos, int player);
|
||||||
bool isVisible(const CGObjectInstance *obj, int player);
|
bool isVisible(const CGObjectInstance *obj, int player);
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include "stdafx.h"
|
||||||
#include "../lib/CCampaignHandler.h"
|
#include "../lib/CCampaignHandler.h"
|
||||||
#include "../StartInfo.h"
|
#include "../StartInfo.h"
|
||||||
#include "../lib/CArtHandler.h"
|
#include "../lib/CArtHandler.h"
|
||||||
@ -17,16 +18,7 @@
|
|||||||
#include "../lib/VCMIDirs.h"
|
#include "../lib/VCMIDirs.h"
|
||||||
#include "../client/CSoundBase.h"
|
#include "../client/CSoundBase.h"
|
||||||
#include "CGameHandler.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>
|
|
||||||
#include <boost/assign/list_of.hpp>
|
|
||||||
#include <boost/random/linear_congruential.hpp>
|
|
||||||
#include <fstream>
|
|
||||||
#include <boost/lexical_cast.hpp>
|
|
||||||
#include <boost/system/system_error.hpp>
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CGameHandler.cpp, part of VCMI engine
|
* CGameHandler.cpp, part of VCMI engine
|
||||||
@ -313,237 +305,16 @@ void CGameHandler::changeSecSkill( int ID, int which, int val, bool abs/*=false*
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance * army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank, boost::function<void(BattleResult*)> cb, const CGTownInstance *town)
|
void CGameHandler::startBattle( const CArmedInstance *armies[2], int3 tile, const CGHeroInstance *heroes[2], bool creatureBank, boost::function<void(BattleResult*)> cb, const CGTownInstance *town /*= NULL*/ )
|
||||||
{
|
{
|
||||||
battleEndCallback = new boost::function<void(BattleResult*)>(cb);
|
battleEndCallback = new boost::function<void(BattleResult*)>(cb);
|
||||||
bEndArmy1 = army1;
|
bEndArmy1 = armies[0];
|
||||||
bEndArmy2 = army2;
|
bEndArmy2 = armies[1];
|
||||||
{
|
{
|
||||||
BattleInfo *curB = new BattleInfo;
|
setupBattle(tile, armies, heroes, creatureBank, town); //initializes stacks, places creatures on battlefield, blocks and informs player interfaces
|
||||||
curB->side1 = army1->tempOwner;
|
|
||||||
curB->side2 = army2->tempOwner;
|
|
||||||
if(curB->side2 == 254)
|
|
||||||
curB->side2 = 255;
|
|
||||||
setupBattle(curB, tile, army1, army2, hero1, hero2, creatureBank, town); //initializes stacks, places creatures on battlefield, blocks and informs player interfaces
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: pre-tactic stuff, call scripts etc.
|
runBattle();
|
||||||
|
|
||||||
//tactic round
|
|
||||||
{
|
|
||||||
if( (hero1 && hero1->getSecSkillLevel(19)>0) ||
|
|
||||||
( hero2 && hero2->getSecSkillLevel(19)>0) )//someone has tactics
|
|
||||||
{
|
|
||||||
//TODO: tactic round (round -1)
|
|
||||||
NEW_ROUND;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//spells opening battle
|
|
||||||
if (hero1 && hero1->hasBonusOfType(Bonus::OPENING_BATTLE_SPELL))
|
|
||||||
{
|
|
||||||
BonusList bl;
|
|
||||||
hero1->getBonuses(bl, Selector::type(Bonus::OPENING_BATTLE_SPELL));
|
|
||||||
BOOST_FOREACH (Bonus *b, bl)
|
|
||||||
{
|
|
||||||
handleSpellCasting(b->subtype, 3, -1, 0, hero1->tempOwner, NULL, hero2, b->val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (hero2 && hero2->hasBonusOfType(Bonus::OPENING_BATTLE_SPELL))
|
|
||||||
{
|
|
||||||
BonusList bl;
|
|
||||||
hero2->getBonuses(bl, Selector::type(Bonus::OPENING_BATTLE_SPELL));
|
|
||||||
BOOST_FOREACH (Bonus *b, bl)
|
|
||||||
{
|
|
||||||
handleSpellCasting(b->subtype, 3, -1, 1, hero2->tempOwner, NULL, hero1, b->val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//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
|
|
||||||
const CStack *next;
|
|
||||||
while(!battleResult.get() && (next = curB.getNextStack()) && next->willMove())
|
|
||||||
{
|
|
||||||
|
|
||||||
//check for bad morale => freeze
|
|
||||||
int nextStackMorale = next->MoraleVal();
|
|
||||||
if( nextStackMorale < 0 &&
|
|
||||||
!(NBonus::hasOfType(hero1, Bonus::BLOCK_MORALE) || NBonus::hasOfType(hero2, Bonus::BLOCK_MORALE)) //checking if heroes have (or don't have) morale blocking bonuses)
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if( rand()%24 < -2 * nextStackMorale)
|
|
||||||
{
|
|
||||||
//unit loses its turn - empty freeze action
|
|
||||||
BattleAction ba;
|
|
||||||
ba.actionType = BattleAction::BAD_MORALE;
|
|
||||||
ba.additionalInfo = 1;
|
|
||||||
ba.side = !next->attackerOwned;
|
|
||||||
ba.stackNumber = next->ID;
|
|
||||||
sendAndApply(&StartAction(ba));
|
|
||||||
sendAndApply(&EndAction());
|
|
||||||
checkForBattleEnd(stacks); //check if this "action" ended the battle (not likely but who knows...)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(next->hasBonusOfType(Bonus::ATTACKS_NEAREST_CREATURE)) //while in berserk
|
|
||||||
{
|
|
||||||
std::pair<const CStack *, int> attackInfo = curB.getNearestStack(next, boost::logic::indeterminate);
|
|
||||||
if(attackInfo.first != NULL)
|
|
||||||
{
|
|
||||||
BattleAction attack;
|
|
||||||
attack.actionType = BattleAction::WALK_AND_ATTACK;
|
|
||||||
attack.side = !next->attackerOwned;
|
|
||||||
attack.stackNumber = next->ID;
|
|
||||||
|
|
||||||
attack.additionalInfo = attackInfo.first->position;
|
|
||||||
attack.destinationTile = attackInfo.second;
|
|
||||||
|
|
||||||
makeBattleAction(attack);
|
|
||||||
|
|
||||||
checkForBattleEnd(stacks);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
makeStackDoNothing(next);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const CGHeroInstance * curOwner = gs->battleGetOwner(next->ID);
|
|
||||||
|
|
||||||
if( (next->position < 0 && (!curOwner || curOwner->getSecSkillLevel(10) == 0)) //arrow turret, hero has no ballistics
|
|
||||||
|| (next->getCreature()->idNumber == 146 && (!curOwner || curOwner->getSecSkillLevel(20) == 0))) //ballista, hero has no artillery
|
|
||||||
{
|
|
||||||
BattleAction attack;
|
|
||||||
attack.actionType = BattleAction::SHOOT;
|
|
||||||
attack.side = !next->attackerOwned;
|
|
||||||
attack.stackNumber = next->ID;
|
|
||||||
|
|
||||||
for(int g=0; g<gs->curB->stacks.size(); ++g)
|
|
||||||
{
|
|
||||||
if(gs->curB->stacks[g]->owner != next->owner && gs->curB->stacks[g]->alive())
|
|
||||||
{
|
|
||||||
attack.destinationTile = gs->curB->stacks[g]->position;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
makeBattleAction(attack);
|
|
||||||
|
|
||||||
checkForBattleEnd(stacks);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(next->getCreature()->idNumber == 145 && (!curOwner || curOwner->getSecSkillLevel(10) == 0)) //catapult, hero has no ballistics
|
|
||||||
{
|
|
||||||
BattleAction attack;
|
|
||||||
static const int wallHexes[] = {50, 183, 182, 130, 62, 29, 12, 95};
|
|
||||||
|
|
||||||
attack.destinationTile = wallHexes[ rand()%ARRAY_COUNT(wallHexes) ];
|
|
||||||
attack.actionType = BattleAction::CATAPULT;
|
|
||||||
attack.additionalInfo = 0;
|
|
||||||
attack.side = !next->attackerOwned;
|
|
||||||
attack.stackNumber = next->ID;
|
|
||||||
|
|
||||||
makeBattleAction(attack);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(next->getCreature()->idNumber == 147 && (!curOwner || curOwner->getSecSkillLevel(27) == 0)) //first aid tent, hero has no first aid
|
|
||||||
{
|
|
||||||
BattleAction heal;
|
|
||||||
|
|
||||||
std::vector< const CStack * > possibleStacks;
|
|
||||||
for (int v=0; v<gs->curB->stacks.size(); ++v)
|
|
||||||
{
|
|
||||||
const CStack * cstack = gs->curB->stacks[v];
|
|
||||||
if (cstack->owner == next->owner && cstack->firstHPleft < cstack->MaxHealth() && cstack->alive()) //it's friendly and not fully healthy
|
|
||||||
{
|
|
||||||
possibleStacks.push_back(cstack);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(possibleStacks.size() == 0)
|
|
||||||
{
|
|
||||||
//nothing to heal
|
|
||||||
makeStackDoNothing(next);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//heal random creature
|
|
||||||
const CStack * toBeHealed = possibleStacks[ rand()%possibleStacks.size() ];
|
|
||||||
heal.actionType = BattleAction::STACK_HEAL;
|
|
||||||
heal.additionalInfo = 0;
|
|
||||||
heal.destinationTile = toBeHealed->position;
|
|
||||||
heal.side = !next->attackerOwned;
|
|
||||||
heal.stackNumber = next->ID;
|
|
||||||
|
|
||||||
makeBattleAction(heal);
|
|
||||||
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int numberOfAsks = 1;
|
|
||||||
bool breakOuter = false;
|
|
||||||
do
|
|
||||||
{//ask interface and wait for answer
|
|
||||||
if(!battleResult.get())
|
|
||||||
{
|
|
||||||
BattleSetActiveStack sas;
|
|
||||||
sas.stack = next->ID;
|
|
||||||
sendAndApply(&sas);
|
|
||||||
boost::unique_lock<boost::mutex> lock(battleMadeAction.mx);
|
|
||||||
while(next->alive() && (!battleMadeAction.data && !battleResult.get())) //active stack hasn't made its action and battle is still going
|
|
||||||
battleMadeAction.cond.wait(lock);
|
|
||||||
battleMadeAction.data = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(battleResult.get()) //don't touch it, battle could be finished while waiting got action
|
|
||||||
{
|
|
||||||
breakOuter = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
//we're after action, all results applied
|
|
||||||
checkForBattleEnd(stacks); //check if this action ended the battle
|
|
||||||
|
|
||||||
//check for good morale
|
|
||||||
nextStackMorale = next->MoraleVal();
|
|
||||||
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()
|
|
||||||
&& nextStackMorale > 0
|
|
||||||
&& !(NBonus::hasOfType(hero1, Bonus::BLOCK_MORALE) || NBonus::hasOfType(hero2, Bonus::BLOCK_MORALE)) //checking if heroes have (or don't have) morale blocking bonuses
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if(rand()%24 < nextStackMorale) //this stack hasn't got morale this turn
|
|
||||||
++numberOfAsks; //move this stack once more
|
|
||||||
}
|
|
||||||
|
|
||||||
--numberOfAsks;
|
|
||||||
} while (numberOfAsks > 0);
|
|
||||||
|
|
||||||
if (breakOuter)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
endBattle(tile, hero1, hero2);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2)
|
void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2)
|
||||||
@ -1294,7 +1065,10 @@ void CGameHandler::run(bool resume)
|
|||||||
ui8 pom;
|
ui8 pom;
|
||||||
//ui32 seed;
|
//ui32 seed;
|
||||||
if(!resume)
|
if(!resume)
|
||||||
(*cc) << gs->initialOpts << gs->map->checksum << gs->seed; // gs->scenarioOps
|
{
|
||||||
|
ui32 sum = gs->map ? gs->map->checksum : 612;
|
||||||
|
(*cc) << gs->initialOpts << sum << gs->seed; // gs->scenarioOps
|
||||||
|
}
|
||||||
|
|
||||||
(*cc) >> quantity; //how many players will be handled at that client
|
(*cc) >> quantity; //how many players will be handled at that client
|
||||||
|
|
||||||
@ -1321,6 +1095,12 @@ void CGameHandler::run(bool resume)
|
|||||||
boost::thread(boost::bind(&CGameHandler::handleConnection,this,pom,boost::ref(**i)));
|
boost::thread(boost::bind(&CGameHandler::handleConnection,this,pom,boost::ref(**i)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(gs->scenarioOps->mode == StartInfo::DUEL)
|
||||||
|
{
|
||||||
|
runBattle();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
while (!end2)
|
while (!end2)
|
||||||
{
|
{
|
||||||
if(!resume)
|
if(!resume)
|
||||||
@ -1382,336 +1162,13 @@ namespace CGH
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameHandler::setupBattle(BattleInfo * curB, int3 tile, const CArmedInstance *army1, const CArmedInstance *army2, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool creatureBank, const CGTownInstance *town)
|
void CGameHandler::setupBattle( int3 tile, const CArmedInstance *armies[2], const CGHeroInstance *heroes[2], bool creatureBank, const CGTownInstance *town )
|
||||||
{
|
{
|
||||||
battleResult.set(NULL);
|
battleResult.set(NULL);
|
||||||
std::vector<CStack*> & stacks = (curB->stacks);
|
|
||||||
|
|
||||||
curB->tile = tile;
|
|
||||||
curB->belligerents[0] = const_cast<CArmedInstance*>(army1);
|
|
||||||
curB->belligerents[1] = const_cast<CArmedInstance*>(army2);
|
|
||||||
curB->heroes[0] = const_cast<CGHeroInstance*>(hero1);
|
|
||||||
curB->heroes[1] = const_cast<CGHeroInstance*>(hero2);
|
|
||||||
curB->round = -2;
|
|
||||||
curB->activeStack = -1;
|
|
||||||
|
|
||||||
if(town)
|
|
||||||
{
|
|
||||||
curB->tid = town->id;
|
|
||||||
curB->siege = town->fortLevel();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
curB->tid = -1;
|
|
||||||
curB->siege = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//reading battleStartpos
|
|
||||||
std::ifstream positions;
|
|
||||||
positions.open(DATA_DIR "/config/battleStartpos.txt", std::ios_base::in|std::ios_base::binary);
|
|
||||||
if(!positions.is_open())
|
|
||||||
{
|
|
||||||
tlog1<<"Unable to open battleStartpos.txt!"<<std::endl;
|
|
||||||
}
|
|
||||||
std::string dump;
|
|
||||||
positions>>dump; positions>>dump;
|
|
||||||
std::vector< std::vector<int> > attackerLoose, defenderLoose, attackerTight, defenderTight, attackerCreBank, defenderCreBank;
|
|
||||||
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>>dump;
|
|
||||||
positions>>dump;
|
|
||||||
CGH::readItTo(positions, attackerCreBank);
|
|
||||||
positions>>dump;
|
|
||||||
CGH::readItTo(positions, defenderCreBank);
|
|
||||||
positions.close();
|
|
||||||
//battleStartpos read
|
|
||||||
|
|
||||||
int k = 0; //stack serial
|
|
||||||
for(TSlots::const_iterator i = army1->Slots().begin(); i!=army1->Slots().end(); i++, k++)
|
|
||||||
{
|
|
||||||
int pos;
|
|
||||||
if(creatureBank)
|
|
||||||
pos = attackerCreBank[army1->stacksCount()-1][k];
|
|
||||||
else if(army1->formation)
|
|
||||||
pos = attackerTight[army1->stacksCount()-1][k];
|
|
||||||
else
|
|
||||||
pos = attackerLoose[army1->stacksCount()-1][k];
|
|
||||||
|
|
||||||
CStack * stack = curB->generateNewStack(*i->second, stacks.size(), true, i->first, pos);
|
|
||||||
stacks.push_back(stack);
|
|
||||||
}
|
|
||||||
|
|
||||||
k = 0;
|
|
||||||
for(TSlots::const_iterator i = army2->Slots().begin(); i!=army2->Slots().end(); i++, k++)
|
|
||||||
{
|
|
||||||
int pos;
|
|
||||||
if(creatureBank)
|
|
||||||
pos = defenderCreBank[army2->stacksCount()-1][k];
|
|
||||||
else if(army2->formation)
|
|
||||||
pos = defenderTight[army2->stacksCount()-1][k];
|
|
||||||
else
|
|
||||||
pos = defenderLoose[army2->stacksCount()-1][k];
|
|
||||||
|
|
||||||
CStack * stack = curB->generateNewStack(*i->second, stacks.size(), false, i->first, pos);
|
|
||||||
stacks.push_back(stack);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(unsigned g=0; g<stacks.size(); ++g) //shifting positions of two-hex creatures
|
|
||||||
{
|
|
||||||
if((stacks[g]->position%17)==1 && stacks[g]->doubleWide() && stacks[g]->attackerOwned)
|
|
||||||
{
|
|
||||||
stacks[g]->position += 1;
|
|
||||||
}
|
|
||||||
else if((stacks[g]->position%17)==15 && stacks[g]->doubleWide() && !stacks[g]->attackerOwned)
|
|
||||||
{
|
|
||||||
stacks[g]->position -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//adding war machines
|
|
||||||
if(hero1)
|
|
||||||
{
|
|
||||||
if(hero1->getArt(13)) //ballista
|
|
||||||
{
|
|
||||||
CStack * stack = curB->generateNewStack(CStackBasicDescriptor(146, 1), stacks.size(), true, 255, 52);
|
|
||||||
stacks.push_back(stack);
|
|
||||||
}
|
|
||||||
if(hero1->getArt(14)) //ammo cart
|
|
||||||
{
|
|
||||||
CStack * stack = curB->generateNewStack(CStackBasicDescriptor(148, 1), stacks.size(), true, 255, 18);
|
|
||||||
stacks.push_back(stack);
|
|
||||||
}
|
|
||||||
if(hero1->getArt(15)) //first aid tent
|
|
||||||
{
|
|
||||||
CStack * stack = curB->generateNewStack(CStackBasicDescriptor(147, 1), stacks.size(), true, 255, 154);
|
|
||||||
stacks.push_back(stack);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(hero2)
|
|
||||||
{
|
|
||||||
//defending hero shouldn't receive ballista (bug #551)
|
|
||||||
if(hero2->getArt(13) && !town) //ballista
|
|
||||||
{
|
|
||||||
CStack * stack = curB->generateNewStack(CStackBasicDescriptor(146, 1), stacks.size(), false, 255, 66);
|
|
||||||
stacks.push_back(stack);
|
|
||||||
}
|
|
||||||
if(hero2->getArt(14)) //ammo cart
|
|
||||||
{
|
|
||||||
CStack * stack = curB->generateNewStack(CStackBasicDescriptor(148, 1), stacks.size(), false, 255, 32);
|
|
||||||
stacks.push_back(stack);
|
|
||||||
}
|
|
||||||
if(hero2->getArt(15)) //first aid tent
|
|
||||||
{
|
|
||||||
CStack * stack = curB->generateNewStack(CStackBasicDescriptor(147, 1), stacks.size(), false, 255, 168);
|
|
||||||
stacks.push_back(stack);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(town && hero1 && town->hasFort()) //catapult
|
|
||||||
{
|
|
||||||
CStack * stack = curB->generateNewStack(CStackBasicDescriptor(145, 1), stacks.size(), true, 255, 120);
|
|
||||||
stacks.push_back(stack);
|
|
||||||
}
|
|
||||||
//war machines added
|
|
||||||
|
|
||||||
switch(curB->siege) //adding towers
|
|
||||||
{
|
|
||||||
|
|
||||||
case 3: //castle
|
|
||||||
{//lower tower / upper tower
|
|
||||||
CStack * stack = curB->generateNewStack(CStackBasicDescriptor(149, 1), stacks.size(), false, 255, -4);
|
|
||||||
stacks.push_back(stack);
|
|
||||||
stack = curB->generateNewStack(CStackBasicDescriptor(149, 1), stacks.size(), false, 255, -3);
|
|
||||||
stacks.push_back(stack);
|
|
||||||
}
|
|
||||||
case 2: //citadel
|
|
||||||
{//main tower
|
|
||||||
CStack * stack = curB->generateNewStack(CStackBasicDescriptor(149, 1), stacks.size(), false, 255, -2);
|
|
||||||
stacks.push_back(stack);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::stable_sort(stacks.begin(),stacks.end(),cmpst);
|
|
||||||
|
|
||||||
//seting up siege
|
|
||||||
if(town && town->hasFort())
|
|
||||||
{
|
|
||||||
for(int b=0; b<ARRAY_COUNT(curB->si.wallState); ++b)
|
|
||||||
{
|
|
||||||
curB->si.wallState[b] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int terType = gs->battleGetBattlefieldType(tile);
|
|
||||||
|
|
||||||
//randomize obstacles
|
|
||||||
if(town == NULL && !creatureBank) //do it only when it's not siege and not creature bank
|
|
||||||
{
|
|
||||||
bool obAv[BFIELD_SIZE]; //availability of hexes for obstacles;
|
|
||||||
std::vector<int> possibleObstacles;
|
|
||||||
|
|
||||||
for(int i=0; i<BFIELD_SIZE; ++i)
|
|
||||||
{
|
|
||||||
if(i%17 < 4 || i%17 > 12)
|
|
||||||
{
|
|
||||||
obAv[i] = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
obAv[i] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(std::map<int, CObstacleInfo>::const_iterator g=VLC->heroh->obstacles.begin(); g!=VLC->heroh->obstacles.end(); ++g)
|
|
||||||
{
|
|
||||||
if(g->second.allowedTerrains[terType-1] == '1') //we need to take terType with -1 because terrain ids start from 1 and allowedTerrains array is indexed from 0
|
|
||||||
{
|
|
||||||
possibleObstacles.push_back(g->first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
srand(time(NULL));
|
|
||||||
if(possibleObstacles.size() > 0) //we cannot place any obstacles when we don't have them
|
|
||||||
{
|
|
||||||
int toBlock = rand()%6 + 6; //how many hexes should be blocked by obstacles
|
|
||||||
while(toBlock>0)
|
|
||||||
{
|
|
||||||
CObstacleInstance coi;
|
|
||||||
coi.uniqueID = curB->obstacles.size();
|
|
||||||
coi.ID = possibleObstacles[rand()%possibleObstacles.size()];
|
|
||||||
coi.pos = rand()%BFIELD_SIZE;
|
|
||||||
std::vector<int> block = VLC->heroh->obstacles[coi.ID].getBlocked(coi.pos);
|
|
||||||
bool badObstacle = false;
|
|
||||||
for(int b=0; b<block.size(); ++b)
|
|
||||||
{
|
|
||||||
if(block[b] < 0 || block[b] >= BFIELD_SIZE || !obAv[block[b]])
|
|
||||||
{
|
|
||||||
badObstacle = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(badObstacle) continue;
|
|
||||||
//obstacle can be placed
|
|
||||||
curB->obstacles.push_back(coi);
|
|
||||||
for(int b=0; b<block.size(); ++b)
|
|
||||||
{
|
|
||||||
if(block[b] >= 0 && block[b] < BFIELD_SIZE)
|
|
||||||
obAv[block[b]] = false;
|
|
||||||
}
|
|
||||||
toBlock -= block.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//giving building bonuses, if siege and we have harrisoned hero
|
|
||||||
if (town)
|
|
||||||
{
|
|
||||||
if (hero2)
|
|
||||||
{
|
|
||||||
for (int i=0; i<4; i++)
|
|
||||||
{
|
|
||||||
int val = town->defenceBonus(i);
|
|
||||||
if (val)
|
|
||||||
{
|
|
||||||
GiveBonus gs;
|
|
||||||
gs.bonus = Bonus(Bonus::ONE_BATTLE, Bonus::PRIMARY_SKILL, Bonus::OBJECT, val, -1, "", i);
|
|
||||||
gs.id = hero2->id;
|
|
||||||
sendAndApply(&gs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else//if we don't have hero - apply separately, if hero present - will be taken from hero bonuses
|
|
||||||
{
|
|
||||||
if(town->subID == 0 && vstd::contains(town->builtBuildings,22)) //castle, brotherhood of sword built
|
|
||||||
for(int g=0; g<stacks.size(); ++g)
|
|
||||||
stacks[g]->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, 2, Bonus::TOWN_STRUCTURE));
|
|
||||||
|
|
||||||
else if(vstd::contains(town->builtBuildings,5)) //tavern is built
|
|
||||||
for(int g=0; g<stacks.size(); ++g)
|
|
||||||
stacks[g]->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, 1, Bonus::TOWN_STRUCTURE));
|
|
||||||
|
|
||||||
if(town->subID == 1 && vstd::contains(town->builtBuildings,21)) //rampart, fountain of fortune is present
|
|
||||||
for(int g=0; g<stacks.size(); ++g)
|
|
||||||
stacks[g]->addNewBonus(makeFeature(Bonus::LUCK, Bonus::ONE_BATTLE, 0, 2, Bonus::TOWN_STRUCTURE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//giving terrain overalay premies
|
|
||||||
int bonusSubtype = -1;
|
|
||||||
switch(terType)
|
|
||||||
{
|
|
||||||
case 9: //magic plains
|
|
||||||
{
|
|
||||||
bonusSubtype = 0;
|
|
||||||
}
|
|
||||||
case 14: //fiery fields
|
|
||||||
{
|
|
||||||
if(bonusSubtype == -1) bonusSubtype = 1;
|
|
||||||
}
|
|
||||||
case 15: //rock lands
|
|
||||||
{
|
|
||||||
if(bonusSubtype == -1) bonusSubtype = 8;
|
|
||||||
}
|
|
||||||
case 16: //magic clouds
|
|
||||||
{
|
|
||||||
if(bonusSubtype == -1) bonusSubtype = 2;
|
|
||||||
}
|
|
||||||
case 17: //lucid pools
|
|
||||||
{
|
|
||||||
if(bonusSubtype == -1) bonusSubtype = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
{ //common part for cases 9, 14, 15, 16, 17
|
|
||||||
curB->addNewBonus(new Bonus(Bonus::ONE_BATTLE, Bonus::MAGIC_SCHOOL_SKILL, Bonus::TERRAIN_OVERLAY, 3, -1, "", bonusSubtype));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 18: //holy ground
|
|
||||||
{
|
|
||||||
curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, +1, Bonus::TERRAIN_OVERLAY)->addLimiter(new CreatureAlignmentLimiter(GOOD)));
|
|
||||||
curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, -1, Bonus::TERRAIN_OVERLAY)->addLimiter(new CreatureAlignmentLimiter(EVIL)));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 19: //clover field
|
|
||||||
{ //+2 luck bonus for neutral creatures
|
|
||||||
curB->addNewBonus(makeFeature(Bonus::LUCK, Bonus::ONE_BATTLE, 0, +2, Bonus::TERRAIN_OVERLAY)->addLimiter(new CreatureFactionLimiter(-1)));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 20: //evil fog
|
|
||||||
{
|
|
||||||
curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, -1, Bonus::TERRAIN_OVERLAY)->addLimiter(new CreatureAlignmentLimiter(GOOD)));
|
|
||||||
curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, +1, Bonus::TERRAIN_OVERLAY)->addLimiter(new CreatureAlignmentLimiter(EVIL)));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 22: //cursed ground
|
|
||||||
{
|
|
||||||
curB->addNewBonus(makeFeature(Bonus::NO_MORALE, Bonus::ONE_BATTLE, 0, 0, Bonus::TERRAIN_OVERLAY));
|
|
||||||
curB->addNewBonus(makeFeature(Bonus::NO_LUCK, Bonus::ONE_BATTLE, 0, 0, Bonus::TERRAIN_OVERLAY));
|
|
||||||
curB->addNewBonus(makeFeature(Bonus::BLOCK_SPELLS_ABOVE_LEVEL, Bonus::ONE_BATTLE, 0, 1, Bonus::TERRAIN_OVERLAY));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//overlay premies given
|
|
||||||
|
|
||||||
//native terrain bonuses
|
|
||||||
int terrain = this->getTile(tile)->tertype;
|
|
||||||
if(town) //during siege always take premies for native terrain of faction
|
|
||||||
terrain = VLC->heroh->nativeTerrains[town->town->typeID];
|
|
||||||
|
|
||||||
ILimiter *nativeTerrain = new CreatureNativeTerrainLimiter(terrain);
|
|
||||||
curB->addNewBonus(makeFeature(Bonus::STACKS_SPEED, Bonus::ONE_BATTLE, 0, 1, Bonus::TERRAIN_NATIVE)->addLimiter(nativeTerrain));
|
|
||||||
curB->addNewBonus(makeFeature(Bonus::PRIMARY_SKILL, Bonus::ONE_BATTLE, PrimarySkill::ATTACK, 1, Bonus::TERRAIN_NATIVE)->addLimiter(nativeTerrain));
|
|
||||||
curB->addNewBonus(makeFeature(Bonus::PRIMARY_SKILL, Bonus::ONE_BATTLE, PrimarySkill::DEFENSE, 1, Bonus::TERRAIN_NATIVE)->addLimiter(nativeTerrain));
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
//send info about battles
|
//send info about battles
|
||||||
BattleStart bs;
|
BattleStart bs;
|
||||||
bs.info = curB;
|
bs.info = gs->setupBattle(tile, armies, heroes, creatureBank, town);
|
||||||
sendAndApply(&bs);
|
sendAndApply(&bs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2285,7 +1742,14 @@ void CGameHandler::startBattleI(const CArmedInstance *army1, const CArmedInstanc
|
|||||||
if(army2->tempOwner < PLAYER_LIMIT)
|
if(army2->tempOwner < PLAYER_LIMIT)
|
||||||
states.setFlag(army2->tempOwner,&PlayerStatus::engagedIntoBattle,true);
|
states.setFlag(army2->tempOwner,&PlayerStatus::engagedIntoBattle,true);
|
||||||
|
|
||||||
boost::thread(boost::bind(&CGameHandler::startBattle, this, army1, army2, tile, hero1, hero2, creatureBank, cb, town));
|
const CArmedInstance *armies[2];
|
||||||
|
armies[0] = army1;
|
||||||
|
armies[1] = army2;
|
||||||
|
const CGHeroInstance*heroes[2];
|
||||||
|
heroes[0] = hero1;
|
||||||
|
heroes[1] = hero2;
|
||||||
|
|
||||||
|
boost::thread(boost::bind(&CGameHandler::startBattle, this, armies, tile, heroes, creatureBank, cb, town));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGameHandler::startBattleI( const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, boost::function<void(BattleResult*)> cb, bool creatureBank )
|
void CGameHandler::startBattleI( const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, boost::function<void(BattleResult*)> cb, bool creatureBank )
|
||||||
@ -5333,6 +4797,226 @@ bool CGameHandler::swapStacks(const StackLocation &sl1, const StackLocation &sl2
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CGameHandler::runBattle()
|
||||||
|
{
|
||||||
|
assert(gs->curB);
|
||||||
|
//TODO: pre-tactic stuff, call scripts etc.
|
||||||
|
|
||||||
|
//tactic round
|
||||||
|
{
|
||||||
|
if( (gs->curB->heroes[0] && gs->curB->heroes[0]->getSecSkillLevel(19)>0) ||
|
||||||
|
( gs->curB->heroes[1] && gs->curB->heroes[1]->getSecSkillLevel(19)>0) )//someone has tactics
|
||||||
|
{
|
||||||
|
//TODO: tactic round (round -1)
|
||||||
|
NEW_ROUND;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//spells opening battle
|
||||||
|
if (gs->curB->heroes[0] && gs->curB->heroes[0]->hasBonusOfType(Bonus::OPENING_BATTLE_SPELL))
|
||||||
|
{
|
||||||
|
BonusList bl;
|
||||||
|
gs->curB->heroes[0]->getBonuses(bl, Selector::type(Bonus::OPENING_BATTLE_SPELL));
|
||||||
|
BOOST_FOREACH (Bonus *b, bl)
|
||||||
|
{
|
||||||
|
handleSpellCasting(b->subtype, 3, -1, 0, gs->curB->heroes[0]->tempOwner, NULL, gs->curB->heroes[1], b->val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (gs->curB->heroes[1] && gs->curB->heroes[1]->hasBonusOfType(Bonus::OPENING_BATTLE_SPELL))
|
||||||
|
{
|
||||||
|
BonusList bl;
|
||||||
|
gs->curB->heroes[1]->getBonuses(bl, Selector::type(Bonus::OPENING_BATTLE_SPELL));
|
||||||
|
BOOST_FOREACH (Bonus *b, bl)
|
||||||
|
{
|
||||||
|
handleSpellCasting(b->subtype, 3, -1, 1, gs->curB->heroes[1]->tempOwner, NULL, gs->curB->heroes[0], b->val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//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
|
||||||
|
const CStack *next;
|
||||||
|
while(!battleResult.get() && (next = curB.getNextStack()) && next->willMove())
|
||||||
|
{
|
||||||
|
|
||||||
|
//check for bad morale => freeze
|
||||||
|
int nextStackMorale = next->MoraleVal();
|
||||||
|
if( nextStackMorale < 0 &&
|
||||||
|
!(NBonus::hasOfType(gs->curB->heroes[0], Bonus::BLOCK_MORALE) || NBonus::hasOfType(gs->curB->heroes[1], Bonus::BLOCK_MORALE)) //checking if gs->curB->heroes have (or don't have) morale blocking bonuses)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if( rand()%24 < -2 * nextStackMorale)
|
||||||
|
{
|
||||||
|
//unit loses its turn - empty freeze action
|
||||||
|
BattleAction ba;
|
||||||
|
ba.actionType = BattleAction::BAD_MORALE;
|
||||||
|
ba.additionalInfo = 1;
|
||||||
|
ba.side = !next->attackerOwned;
|
||||||
|
ba.stackNumber = next->ID;
|
||||||
|
sendAndApply(&StartAction(ba));
|
||||||
|
sendAndApply(&EndAction());
|
||||||
|
checkForBattleEnd(stacks); //check if this "action" ended the battle (not likely but who knows...)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(next->hasBonusOfType(Bonus::ATTACKS_NEAREST_CREATURE)) //while in berserk
|
||||||
|
{
|
||||||
|
std::pair<const CStack *, int> attackInfo = curB.getNearestStack(next, boost::logic::indeterminate);
|
||||||
|
if(attackInfo.first != NULL)
|
||||||
|
{
|
||||||
|
BattleAction attack;
|
||||||
|
attack.actionType = BattleAction::WALK_AND_ATTACK;
|
||||||
|
attack.side = !next->attackerOwned;
|
||||||
|
attack.stackNumber = next->ID;
|
||||||
|
|
||||||
|
attack.additionalInfo = attackInfo.first->position;
|
||||||
|
attack.destinationTile = attackInfo.second;
|
||||||
|
|
||||||
|
makeBattleAction(attack);
|
||||||
|
|
||||||
|
checkForBattleEnd(stacks);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
makeStackDoNothing(next);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CGHeroInstance * curOwner = gs->battleGetOwner(next->ID);
|
||||||
|
|
||||||
|
if( (next->position < 0 && (!curOwner || curOwner->getSecSkillLevel(10) == 0)) //arrow turret, hero has no ballistics
|
||||||
|
|| (next->getCreature()->idNumber == 146 && (!curOwner || curOwner->getSecSkillLevel(20) == 0))) //ballista, hero has no artillery
|
||||||
|
{
|
||||||
|
BattleAction attack;
|
||||||
|
attack.actionType = BattleAction::SHOOT;
|
||||||
|
attack.side = !next->attackerOwned;
|
||||||
|
attack.stackNumber = next->ID;
|
||||||
|
|
||||||
|
for(int g=0; g<gs->curB->stacks.size(); ++g)
|
||||||
|
{
|
||||||
|
if(gs->curB->stacks[g]->owner != next->owner && gs->curB->stacks[g]->alive())
|
||||||
|
{
|
||||||
|
attack.destinationTile = gs->curB->stacks[g]->position;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
makeBattleAction(attack);
|
||||||
|
|
||||||
|
checkForBattleEnd(stacks);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(next->getCreature()->idNumber == 145 && (!curOwner || curOwner->getSecSkillLevel(10) == 0)) //catapult, hero has no ballistics
|
||||||
|
{
|
||||||
|
BattleAction attack;
|
||||||
|
static const int wallHexes[] = {50, 183, 182, 130, 62, 29, 12, 95};
|
||||||
|
|
||||||
|
attack.destinationTile = wallHexes[ rand()%ARRAY_COUNT(wallHexes) ];
|
||||||
|
attack.actionType = BattleAction::CATAPULT;
|
||||||
|
attack.additionalInfo = 0;
|
||||||
|
attack.side = !next->attackerOwned;
|
||||||
|
attack.stackNumber = next->ID;
|
||||||
|
|
||||||
|
makeBattleAction(attack);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(next->getCreature()->idNumber == 147 && (!curOwner || curOwner->getSecSkillLevel(27) == 0)) //first aid tent, hero has no first aid
|
||||||
|
{
|
||||||
|
BattleAction heal;
|
||||||
|
|
||||||
|
std::vector< const CStack * > possibleStacks;
|
||||||
|
for (int v=0; v<gs->curB->stacks.size(); ++v)
|
||||||
|
{
|
||||||
|
const CStack * cstack = gs->curB->stacks[v];
|
||||||
|
if (cstack->owner == next->owner && cstack->firstHPleft < cstack->MaxHealth() && cstack->alive()) //it's friendly and not fully healthy
|
||||||
|
{
|
||||||
|
possibleStacks.push_back(cstack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(possibleStacks.size() == 0)
|
||||||
|
{
|
||||||
|
//nothing to heal
|
||||||
|
makeStackDoNothing(next);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//heal random creature
|
||||||
|
const CStack * toBeHealed = possibleStacks[ rand()%possibleStacks.size() ];
|
||||||
|
heal.actionType = BattleAction::STACK_HEAL;
|
||||||
|
heal.additionalInfo = 0;
|
||||||
|
heal.destinationTile = toBeHealed->position;
|
||||||
|
heal.side = !next->attackerOwned;
|
||||||
|
heal.stackNumber = next->ID;
|
||||||
|
|
||||||
|
makeBattleAction(heal);
|
||||||
|
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int numberOfAsks = 1;
|
||||||
|
bool breakOuter = false;
|
||||||
|
do
|
||||||
|
{//ask interface and wait for answer
|
||||||
|
if(!battleResult.get())
|
||||||
|
{
|
||||||
|
BattleSetActiveStack sas;
|
||||||
|
sas.stack = next->ID;
|
||||||
|
sendAndApply(&sas);
|
||||||
|
boost::unique_lock<boost::mutex> lock(battleMadeAction.mx);
|
||||||
|
while(next->alive() && (!battleMadeAction.data && !battleResult.get())) //active stack hasn't made its action and battle is still going
|
||||||
|
battleMadeAction.cond.wait(lock);
|
||||||
|
battleMadeAction.data = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(battleResult.get()) //don't touch it, battle could be finished while waiting got action
|
||||||
|
{
|
||||||
|
breakOuter = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//we're after action, all results applied
|
||||||
|
checkForBattleEnd(stacks); //check if this action ended the battle
|
||||||
|
|
||||||
|
//check for good morale
|
||||||
|
nextStackMorale = next->MoraleVal();
|
||||||
|
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()
|
||||||
|
&& nextStackMorale > 0
|
||||||
|
&& !(NBonus::hasOfType(gs->curB->heroes[0], Bonus::BLOCK_MORALE) || NBonus::hasOfType(gs->curB->heroes[1], Bonus::BLOCK_MORALE)) //checking if gs->curB->heroes have (or don't have) morale blocking bonuses
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if(rand()%24 < nextStackMorale) //this stack hasn't got morale this turn
|
||||||
|
++numberOfAsks; //move this stack once more
|
||||||
|
}
|
||||||
|
|
||||||
|
--numberOfAsks;
|
||||||
|
} while (numberOfAsks > 0);
|
||||||
|
|
||||||
|
if (breakOuter)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
endBattle(gs->curB->tile, gs->curB->heroes[0], gs->curB->heroes[1]);
|
||||||
|
}
|
||||||
CasualtiesAfterBattle::CasualtiesAfterBattle(const CArmedInstance *army, BattleInfo *bat)
|
CasualtiesAfterBattle::CasualtiesAfterBattle(const CArmedInstance *army, BattleInfo *bat)
|
||||||
{
|
{
|
||||||
int color = army->tempOwner;
|
int color = army->tempOwner;
|
||||||
|
@ -105,7 +105,8 @@ public:
|
|||||||
bool isAllowedExchange(int id1, int id2);
|
bool isAllowedExchange(int id1, int id2);
|
||||||
void giveSpells(const CGTownInstance *t, const CGHeroInstance *h);
|
void giveSpells(const CGTownInstance *t, const CGHeroInstance *h);
|
||||||
int moveStack(int stack, int dest); //returned value - travelled distance
|
int moveStack(int stack, int dest); //returned value - travelled distance
|
||||||
void startBattle(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank, boost::function<void(BattleResult*)> cb, const CGTownInstance *town = NULL); //use hero=NULL for no hero
|
void startBattle(const CArmedInstance *armies[2], int3 tile, const CGHeroInstance *heroes[2], bool creatureBank, boost::function<void(BattleResult*)> cb, const CGTownInstance *town = NULL); //use hero=NULL for no hero
|
||||||
|
void runBattle();
|
||||||
void checkLossVictory(ui8 player);
|
void checkLossVictory(ui8 player);
|
||||||
void winLoseHandle(ui8 players=255); //players: bit field - colours of players to be checked; default: all
|
void winLoseHandle(ui8 players=255); //players: bit field - colours of players to be checked; default: all
|
||||||
void getLossVicMessage(ui8 player, ui8 standard, bool victory, InfoWindow &out) const;
|
void getLossVicMessage(ui8 player, ui8 standard, bool victory, InfoWindow &out) const;
|
||||||
@ -119,7 +120,7 @@ public:
|
|||||||
void prepareAttack(BattleAttack &bat, const CStack *att, const CStack *def, int distance); //distance - number of hexes travelled before attacking
|
void prepareAttack(BattleAttack &bat, const CStack *att, const CStack *def, int distance); //distance - number of hexes travelled before attacking
|
||||||
void prepareAttacked(BattleStackAttacked &bsa, const CStack *def);
|
void prepareAttacked(BattleStackAttacked &bsa, const CStack *def);
|
||||||
void checkForBattleEnd( std::vector<CStack*> &stacks );
|
void checkForBattleEnd( std::vector<CStack*> &stacks );
|
||||||
void setupBattle( BattleInfo * curB, int3 tile, const CArmedInstance *army1, const CArmedInstance *army2, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool creatureBank, const CGTownInstance *town);
|
void setupBattle(int3 tile, const CArmedInstance *armies[2], const CGHeroInstance *heroes[2], bool creatureBank, const CGTownInstance *town);
|
||||||
|
|
||||||
CGameHandler(void);
|
CGameHandler(void);
|
||||||
~CGameHandler(void);
|
~CGameHandler(void);
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
|
#include "stdafx.h"
|
||||||
#include "../lib/CCampaignHandler.h"
|
#include "../lib/CCampaignHandler.h"
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
#include <boost/asio.hpp>
|
|
||||||
#include "../global.h"
|
#include "../global.h"
|
||||||
#include "../lib/Connection.h"
|
#include "../lib/Connection.h"
|
||||||
#include "../lib/CArtHandler.h"
|
#include "../lib/CArtHandler.h"
|
||||||
@ -18,9 +16,6 @@
|
|||||||
#include <tchar.h>
|
#include <tchar.h>
|
||||||
#endif
|
#endif
|
||||||
#include "CVCMIServer.h"
|
#include "CVCMIServer.h"
|
||||||
#include <boost/crc.hpp>
|
|
||||||
#include <boost/interprocess/mapped_region.hpp>
|
|
||||||
#include <boost/interprocess/shared_memory_object.hpp>
|
|
||||||
#include "../StartInfo.h"
|
#include "../StartInfo.h"
|
||||||
#include "../lib/map.h"
|
#include "../lib/map.h"
|
||||||
#include "../lib/CLodHandler.h"
|
#include "../lib/CLodHandler.h"
|
||||||
@ -28,8 +23,6 @@
|
|||||||
#include "../lib/VCMI_Lib.h"
|
#include "../lib/VCMI_Lib.h"
|
||||||
#include "../lib/VCMIDirs.h"
|
#include "../lib/VCMIDirs.h"
|
||||||
#include "CGameHandler.h"
|
#include "CGameHandler.h"
|
||||||
#include <boost/thread.hpp>
|
|
||||||
#include <boost/foreach.hpp>
|
|
||||||
#include "../lib/CMapInfo.h"
|
#include "../lib/CMapInfo.h"
|
||||||
|
|
||||||
std::string NAME_AFFIX = "server";
|
std::string NAME_AFFIX = "server";
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#include "stdafx.h"
|
||||||
#include "../lib/NetPacks.h"
|
#include "../lib/NetPacks.h"
|
||||||
#include "CGameHandler.h"
|
#include "CGameHandler.h"
|
||||||
#include "../lib/CObjectHandler.h"
|
#include "../lib/CObjectHandler.h"
|
||||||
|
1
server/stdafx.cpp
Normal file
1
server/stdafx.cpp
Normal file
@ -0,0 +1 @@
|
|||||||
|
#include "stdafx.h"
|
24
server/stdafx.h
Normal file
24
server/stdafx.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#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>
|
||||||
|
#include <boost/assign/list_of.hpp>
|
||||||
|
#include <boost/random/linear_congruential.hpp>
|
||||||
|
#include <fstream>
|
||||||
|
#include <boost/lexical_cast.hpp>
|
||||||
|
#include <boost/system/system_error.hpp>
|
||||||
|
#include <boost/function.hpp>
|
||||||
|
#include <boost/thread.hpp>
|
||||||
|
#include <set>
|
||||||
|
#include <map>
|
||||||
|
#include "../global.h"
|
||||||
|
|
||||||
|
#include <boost/crc.hpp>
|
||||||
|
#include <boost/interprocess/mapped_region.hpp>
|
||||||
|
#include <boost/interprocess/shared_memory_object.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <boost/thread.hpp>
|
||||||
|
#include <boost/foreach.hpp>
|
Loading…
Reference in New Issue
Block a user