1
0
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:
mateuszb 2010-12-22 20:14:40 +00:00
parent 49083c4e5a
commit af2c4633ad
23 changed files with 1088 additions and 751 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -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");
}

View File

@ -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)
{ {

View File

@ -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
View 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
View 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
View 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&gt;</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&gt;</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
View 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
View File

@ -0,0 +1 @@
#include "stdafx.h"

2
StupidAI/stdafx.h Normal file
View File

@ -0,0 +1,2 @@
#pragma once
#include "../../AI_Base.h"

View File

@ -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:

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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";

View File

@ -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
View File

@ -0,0 +1 @@
#include "stdafx.h"

24
server/stdafx.h Normal file
View 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>