1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-03-19 21:10:12 +02:00

[programming challenge]

* stupid AI will print more info
* proper handling of too long processing of battle end calls
* doxygenized some comments
This commit is contained in:
Michał W. Urbańczyk 2011-12-03 23:40:56 +00:00
parent 3fbaaac6d9
commit 85588b6bda
17 changed files with 371 additions and 130 deletions

View File

@ -7,6 +7,7 @@
#include "../../lib/CCreatureHandler.h"
#include <algorithm>
//#include <boost/thread.hpp>
#include "../../lib/CHeroHandler.h"
CBattleCallback * cbc;
@ -204,16 +205,8 @@ void CStupidAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2
{
print("battleStart called");
side = Side;
TStacks myStacks = cb->battleGetStacks(CBattleCallback::ONLY_MINE);
std::cout << "My side: " << side << std::endl
<< "I have " << myStacks.size() << " stacks. They are:\n";
printOpeningReport();
for(int i = 0; i < myStacks.size(); i++)
{
const CStack *s = myStacks.at(i);
tlog5 << format("%2d) Stack of %4d %s.\n\tAttack:\t%4d, \n\tDefense:\t%4d, \n\tHP:\t%4d\n\tDamage:\t%4d-%d\n")
% i % s->count % s->getCreature()->namePl % s->Attack() % s->Defense() % s->MaxHealth() % s->getMinDamage() % s->getMaxDamage();
}
}
void CStupidAI::battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, bool tentHeal, si32 lifeDrainFrom)
@ -276,3 +269,29 @@ BattleAction CStupidAI::goTowards(const CStack * stack, THex hex)
}
}
void CStupidAI::printOpeningReport()
{
TStacks myStacks = cb->battleGetStacks(CBattleCallback::ONLY_MINE);
tlog5 << "My side: " << side << std::endl;
if(const CGHeroInstance *h = cb->battleGetFightingHero(side))
{
tlog5 << boost::format("I have a hero named %s (Type ID=%d)\n") % h->name % h->type->ID;
tlog5 << boost::format("Hero skills: Attack %d, Defense %d, Spell Power %d, Knowledge %d, Mana %d/%d\n")
% h->Attack() % h->Defense() % h->getPrimSkillLevel(PrimarySkill::SPELL_POWER)
% h->getPrimSkillLevel(PrimarySkill::KNOWLEDGE) % h->mana % h->manaLimit();
tlog5 << "Number of known spells: " << h->spells.size() << std::endl;
}
else
tlog5 << "I do not have a hero.\n";
tlog5 << "I have " << myStacks.size() << " stacks. They are:\n";
for(int i = 0; i < myStacks.size(); i++)
{
const CStack *s = myStacks.at(i);
tlog5 << format("%2d) Stack of %4d %s.\n\tAttack:\t\t%4d, \n\tDefense:\t%4d, \n\tHP:\t\t%4d\n\tDamage:\t\t%4d-%d\n")
% (i+1) % s->count % s->getCreature()->namePl % s->Attack() % s->Defense() % s->MaxHealth() % s->getMinDamage() % s->getMaxDamage();
}
}

View File

@ -6,6 +6,7 @@ class CStupidAI : public CBattleGameInterface
CBattleCallback *cb;
void print(const std::string &text) const;
void printOpeningReport();
public:
CStupidAI(void);
~CStupidAI(void);

View File

@ -58,13 +58,13 @@ struct CheckTime
//all ms
const int PROCESS_INFO_TIME = 5;
const int MAKE_DECIDION_TIME = 75;
const int MAKE_DECIDION_TIME = 125;
const int MEASURE_MARGIN = 1;
const int HANGUP_TIME = 50;
const int STARTUP_TIME = 100;
void postInfoCall(int timeUsed);
void postDecisionCall(int timeUsed);
void postDecisionCall(int timeUsed, const std::string &text = "AI was thinking over an action");
struct Bomb
{

View File

@ -22,9 +22,9 @@ void postInfoCall(int timeUsed, int limit)
}
}
void postDecisionCall(int timeUsed)
void postDecisionCall(int timeUsed, const std::string &text/* = "AI was thinking over an action"*/)
{
tlog0 << "AI was thinking over an action for " << timeUsed << " ms.\n";
tlog0 << text << " for " << timeUsed << " ms.\n";
if(timeUsed > MAKE_DECIDION_TIME + MEASURE_MARGIN)
{
tlog1 << "That's too long! AI is disqualified!\n";

View File

@ -20,6 +20,7 @@
#include "../lib/BattleState.h"
#include "../lib/NetPacks.h"
#include "../lib/CThreadHelper.h"
#include "CheckTime.h"
using namespace std;
using namespace boost;
@ -88,10 +89,17 @@ int main(int argc, char** argv)
tlog0 << "Cbc created\n";
if(battleAIName.size())
{
Bomb *b = new Bomb(55 + HANGUP_TIME);
CheckTime timer;
//////////////////////////////////////////////////////////////////////////
cl.ai = CDynLibHandler::getNewBattleAI(battleAIName);
cl.color = color;
tlog0 << "AI created\n";
cl.ai->init(cbc);
//////////////////////////////////////////////////////////////////////////
postDecisionCall(timer.timeSinceStart(), "AI was being created");
b->disarm();
BattleStart bs;
bs.info = gs->curB;

View File

@ -9,6 +9,7 @@
"side" : 0,
"army" : [[10, 40]],
"heroid" : 0,
"heroPrimSkills" : [4, 4, 3, 2],
"spells" : [1,2,3,4]
},
{

View File

@ -75,9 +75,10 @@ struct DLL_EXPORT BattleInfo : public CBonusSystemNode
h & static_cast<CBonusSystemNode&>(*this);
}
//////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//void getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root = NULL) const;
//////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
const CStack * getNextStack() const; //which stack will have turn after current one
void getStackQueue(std::vector<const CStack *> &out, int howMany, int turn = 0, int lastMoved = -1) const; //returns stack in order of their movement action
@ -146,40 +147,87 @@ struct DLL_EXPORT BattleInfo : public CBonusSystemNode
class DLL_EXPORT CStack : public CBonusSystemNode, public CStackBasicDescriptor
{
public:
/// pointer to structure describing stack in garrison that was source of this stack, may be NULL (eg. summoned creatures and War Machines)
const CStackInstance *base;
ui32 ID; //unique ID of stack
/// unique ID of stack
ui32 ID;
/// how many creatures stack counted at the beginning of battle
ui32 baseAmount;
ui32 firstHPleft; //HP of first creature in stack
ui8 owner, slot; //owner - player colour (255 for neutrals), slot - position in garrison (may be 255 for neutrals/called creatures)
ui8 attackerOwned; //if true, this stack is owned by attakcer (this one from left hand side of battle)
THex position; //position on battlefield; -2 - keep, -3 - lower tower, -4 - upper tower
ui8 counterAttacks; //how many counter attacks can be performed more in this turn (by default set at the beginning of the round to 1)
si16 shots; //how many shots left
ui8 casts; //how many casts left
/// HP of first creature in stack
ui32 firstHPleft;
/// owner - player colour (255 for neutrals), slot - position in garrison (may be 255 for neutrals/called creatures)
ui8 owner, slot;
/// if true, this stack is owned by attakcer (this one from left hand side of battle)
ui8 attackerOwned;
/// position on battlefield; -2 - keep, -3 - lower tower, -4 - upper tower
THex position;
/// how many counter attacks can be performed more in this turn (by default set at the beginning of the round to 1)
ui8 counterAttacks;
/// how many shots left
si16 shots;
/// how many casts left
ui8 casts;
std::set<ECombatInfo> state;
//overrides
const CCreature* getCreature() const {return type;}
CStack(const CStackInstance *base, int O, int I, bool AO, int S); //c-tor
CStack(const CStackBasicDescriptor *stack, int O, int I, bool AO, int S = 255); //c-tor
CStack(); //c-tor
/// c-tor
CStack(const CStackInstance *base, int O, int I, bool AO, int S);
/// c-tor
CStack(const CStackBasicDescriptor *stack, int O, int I, bool AO, int S = 255);
/// c-tor
CStack();
~CStack();
std::string nodeName() const OVERRIDE;
void init(); //set initial (invalid) values
void postInit(); //used to finish initialization when inheriting creature parameters is working
const Bonus * getEffect(ui16 id, int turn = 0) const; //effect id (SP)
ui8 howManyEffectsSet(ui16 id) const; //returns amount of effects with given id set for this stack
bool willMove(int turn = 0) const; //if stack has remaining move this turn
bool ableToRetaliate() const; //if stack can retaliate after attacked
bool moved(int turn = 0) const; //if stack was already moved this turn
bool canMove(int turn = 0) const; //if stack can move
ui32 Speed(int turn = 0) const; //get speed of creature with all modificators
/// set initial (invalid) values
void init();
/// used to finish initialization when inheriting creature parameters is working
void postInit();
/// effect id (SP)
const Bonus * getEffect(ui16 id, int turn = 0) const;
/// returns amount of effects with given id set for this stack
ui8 howManyEffectsSet(ui16 id) const;
/// if stack has remaining move this turn
bool willMove(int turn = 0) const;
/// if stack can retaliate after attacked
bool ableToRetaliate() const;
/// if stack was already moved this turn
bool moved(int turn = 0) const;
/// if stack can move
bool canMove(int turn = 0) const;
/// get speed of creature with all modificators
ui32 Speed(int turn = 0) const;
static void stackEffectToFeature(std::vector<Bonus> & sf, const Bonus & sse);
std::vector<si32> activeSpells() const; //returns vector of active spell IDs sorted by time of cast
const CGHeroInstance *getMyHero() const; //if stack belongs to hero (directly or was by him summoned) returns hero, NULL otherwise
/// returns vector of active spell IDs sorted by time of cast
std::vector<si32> activeSpells() const;
/// if stack belongs to hero (directly or was by him summoned) returns hero, NULL otherwise
const CGHeroInstance *getMyHero() const;
static inline Bonus featureGenerator(Bonus::BonusType type, si16 subtype, si32 value, ui16 turnsRemain, si32 additionalInfo = 0, si32 limit = Bonus::NO_LIMIT)
{
@ -199,13 +247,25 @@ public:
static bool isMeleeAttackPossible(const CStack * attacker, const CStack * defender, THex attackerPos = THex::INVALID, THex defenderPos = THex::INVALID);
/// checks if stack is double wide (occupies two hexes)
bool doubleWide() const;
THex occupiedHex() const; //returns number of occupied hex (not the position) if stack is double wide; otherwise -1
std::vector<THex> getHexes() const; //up to two occupied hexes, starting from front
bool coversPos(THex position) const; //checks also if unit is double-wide
std::vector<THex> getSurroundingHexes(THex attackerPos = THex::INVALID) const; // get six or 8 surrounding hexes depending on creature size
void prepareAttacked(BattleStackAttacked &bsa) const; //requires bsa.damageAmout filled
/// returns number of occupied hex (not the position) if stack is double wide; otherwise -1
THex occupiedHex() const;
/// up to two occupied hexes, starting from front
std::vector<THex> getHexes() const;
/// checks also if unit is double-wide
bool coversPos(THex position) const;
/// get six or 8 surrounding hexes depending on creature size
std::vector<THex> getSurroundingHexes(THex attackerPos = THex::INVALID) const;
/// requires bsa.damageAmout filled
void prepareAttacked(BattleStackAttacked &bsa) const;
template <typename Handler> void serialize(Handler &h, const int version)
{
@ -236,7 +296,9 @@ public:
}
}
bool alive() const //determines if stack is alive
/// determines if stack is alive
bool alive() const
{
return vstd::contains(state,ALIVE);
}

View File

@ -19,11 +19,19 @@ public:
class DLL_EXPORT IBattleCallback
{
public:
bool waitTillRealize; //if true, request functions will return after they are realized by server
bool unlockGsWhenWaiting;//if true after sending each request, gs mutex will be unlocked so the changes can be applied; NOTICE caller must have gs mx locked prior to any call to actiob callback!
/// if true, request functions will return after they are realized by server
bool waitTillRealize;
/// if true after sending each request, gs mutex will be unlocked so the changes can be applied; NOTICE caller must have gs mx locked prior to any call to actiob callback!
bool unlockGsWhenWaiting;
//battle
virtual int battleMakeAction(BattleAction* action)=0;//for casting spells by hero - DO NOT use it for moving active stack
virtual bool battleMakeTacticAction(BattleAction * action) =0; // performs tactic phase actions
/// for casting spells by hero - DO NOT use it for moving active stack
virtual int battleMakeAction(BattleAction* action)=0;
/// performs tactic phase actions
virtual bool battleMakeTacticAction(BattleAction * action) =0;
};
class DLL_EXPORT CBattleCallback : public IBattleCallback, public CBattleInfoCallback
@ -35,8 +43,12 @@ protected:
public:
CBattleCallback(CGameState *GS, int Player, IConnectionHandler *C);
int battleMakeAction(BattleAction* action) OVERRIDE;//for casting spells by hero - DO NOT use it for moving active stack
bool battleMakeTacticAction(BattleAction * action) OVERRIDE; // performs tactic phase actions
/// for casting spells by hero - DO NOT use it for moving active stack
int battleMakeAction(BattleAction* action) OVERRIDE;
/// performs tactic phase actions
bool battleMakeTacticAction(BattleAction * action) OVERRIDE;
friend class CCallback;
friend class CClient;

View File

@ -22,7 +22,7 @@
template<typename rett>
rett * createAny(std::string dllname, std::string methodName)
{
char temp[50];
char temp[500];
rett * ret=NULL;
rett*(*getAI)();
void(*getName)(char*);

View File

@ -33,6 +33,7 @@
#include "../lib/JsonNode.h"
#include <boost/algorithm/string/predicate.hpp>
#include "BattleAction.h"
//#include <windows.h>
boost::rand48 ran;
class CGObjectInstance;
@ -967,10 +968,14 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed )
CArmedInstance *obj = NULL;
if(dp.sides[i].heroId >= 0)
{
const DuelParameters::SideSettings &ss = dp.sides[i];
CGHeroInstance *h = new CGHeroInstance();
armies[i] = heroes[i] = h;
obj = h;
h->subID = dp.sides[i].heroId;
h->subID = ss.heroId;
for(int i = 0; i < ss.heroPrimSkills.size(); i++)
h->pushPrimSkill(i, ss.heroPrimSkills[i]);
h->initHero(h->subID);
obj->initObj();
}
@ -2812,7 +2817,23 @@ DuelParameters DuelParameters::fromJSON(const std::string &fname)
i++;
}
if(n["heroid"].getType() == JsonNode::DATA_FLOAT)
ss.heroId = n["heroid"].Float();
else
ss.heroId = -1;
// int msgboxID = MessageBox(
// NULL,
// "Resource not available\nDo you want to try again?",
// "Account Details",
// MB_ICONWARNING | MB_CANCELTRYCONTINUE | MB_DEFBUTTON2
// );
BOOST_FOREACH(const JsonNode &n, n["heroPrimSkills"].Vector())
ss.heroPrimSkills.push_back(n.Float());
assert(ss.heroPrimSkills.empty() || ss.heroPrimSkills.size() == PRIMARY_SKILLS);
if(ss.heroId != -1)
BOOST_FOREACH(const JsonNode &spell, n["spells"].Vector())
ss.spells.insert(spell.Float());

View File

@ -297,12 +297,13 @@ struct DLL_EXPORT DuelParameters
} stacks[ARMY_SIZE];
si32 heroId; //-1 if none
std::vector<si32> heroPrimSkills; //may be empty
std::set<si32> spells;
SideSettings();
template <typename Handler> void serialize(Handler &h, const int version)
{
h & stacks & heroId & spells;
h & stacks & heroId & heroPrimSkills & spells;
}
} sides[2];

View File

@ -49,8 +49,10 @@ void CThreadHelper::processTasks()
}
}
static std::list<std::string> names;
void setThreadName(long threadID, const std::string &name)
{
names.push_back(name);
#ifdef _WIN32
//follows http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
const DWORD MS_VC_EXCEPTION=0x406D1388;
@ -65,10 +67,12 @@ void setThreadName(long threadID, const std::string &name)
#pragma pack(pop)
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = name.c_str();
info.szName = names.back().c_str();
info.dwThreadID = threadID;
info.dwFlags = 0;
tlog5 << "Thread " << GetCurrentThreadId() << " will be known as " << name << std::endl;
__try
{
RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );

View File

@ -88,38 +88,95 @@ public:
ONLY_MINE, ONLY_ENEMY, MINE_AND_ENEMY
};
//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(THex 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(THex pos, bool onlyAlive = true); //returns stack info by given pos
THex battleGetPos(int stack); //returns position (tile ID) of stack
TStacks battleGetStacks(EStackOwnership whose = MINE_AND_ENEMY, bool onlyAlive = true); //returns stacks on battlefield
void getStackQueue( std::vector<const CStack *> &out, int howMany ); //returns vector of stack in order of their move sequence
void battleGetStackCountOutsideHexes(bool *ac); // returns hexes which when in front of a stack cause us to move the amount box back
std::vector<THex> battleGetAvailableHexes(const CStack * stack, bool addOccupiable, std::vector<THex> * attackable = NULL); //returns numbers of hexes reachable by creature with id ID
std::vector<int> battleGetDistances(const CStack * stack, THex hex = THex::INVALID, THex * predecessors = NULL); //returns vector of distances to [dest hex number]
/// Return value: 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 battleGetBattlefieldType();
/// returns bitfield
int battleGetObstaclesAtTile(THex tile);
/// returns all obstacles on the battlefield
std::vector<CObstacleInstance> battleGetAllObstacles();
/// returns stack info by given ID
const CStack * battleGetStackByID(int ID, bool onlyAlive = true);
/// returns stack info by given pos
const CStack * battleGetStackByPos(THex pos, bool onlyAlive = true);
/// returns position (tile ID) of stack
THex battleGetPos(int stack);
/// returns stacks on battlefield
TStacks battleGetStacks(EStackOwnership whose = MINE_AND_ENEMY, bool onlyAlive = true);
/// returns vector of stack in order of their move sequence
void getStackQueue( std::vector<const CStack *> &out, int howMany );
/// returns hexes which when in front of a stack cause us to move the amount box back
void battleGetStackCountOutsideHexes(bool *ac);
/// returns numbers of hexes reachable by creature with id ID
std::vector<THex> battleGetAvailableHexes(const CStack * stack, bool addOccupiable, std::vector<THex> * attackable = NULL);
/// returns vector of distances to [dest hex number]
std::vector<int> battleGetDistances(const CStack * stack, THex hex = THex::INVALID, THex * predecessors = NULL);
std::set<THex> battleGetAttackedHexes(const CStack* attacker, THex destinationTile, THex attackerPos = THex::INVALID);
bool battleCanShoot(const CStack * stack, THex dest); //returns true if unit with id ID can shoot to dest
bool battleCanCastSpell(); //returns true, if caller can cast a spell
SpellCasting::ESpellCastProblem battleCanCastThisSpell(const CSpell * spell); //determines if given spell can be casted (and returns problem description)
bool battleCanFlee(); //returns true if caller can flee from the battle
int battleGetSurrenderCost(); //returns cost of surrendering battle, -1 if surrendering is not possible
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(THex hex); //returns part of destructible wall / gate / keep under given hex or -1 if not found
TDmgRange battleEstimateDamage(const CStack * attacker, const CStack * defender, TDmgRange * retaliationDmg = NULL); //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 to given side (0 - attacker, 1 - defender)
si8 battleHasDistancePenalty(const CStack * stack, THex destHex); //checks if given stack has distance penalty
si8 battleHasWallPenalty(const CStack * stack, THex destHex); //checks if given stack has wall penalty
si8 battleCanTeleportTo(const CStack * stack, THex destHex, int telportLevel); //checks if teleportation of given stack to given position can take place
si8 battleGetTacticDist(); //returns tactic distance for calling player or 0 if player is not in tactic phase
ui8 battleGetMySide(); //return side of player in battle (attacker/defender)
/// returns true if unit with id ID can shoot to dest
bool battleCanShoot(const CStack * stack, THex dest);
/// returns true, if caller can cast a spell
bool battleCanCastSpell();
/// determines if given spell can be casted (and returns problem description)
SpellCasting::ESpellCastProblem battleCanCastThisSpell(const CSpell * spell);
/// returns true if caller can flee from the battle
bool battleCanFlee();
/// returns cost of surrendering battle, -1 if surrendering is not possible
int battleGetSurrenderCost();
/// returns defended town if current battle is a siege, NULL instead
const CGTownInstance * battleGetDefendedTown();
/// 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
ui8 battleGetWallState(int partOfWall);
/// returns part of destructible wall / gate / keep under given hex or -1 if not found
int battleGetWallUnderHex(THex hex);
/// 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>
TDmgRange battleEstimateDamage(const CStack * attacker, const CStack * defender, TDmgRange * retaliationDmg = NULL);
/// returns 0 when there is no siege, 1 if fort, 2 is citadel, 3 is castle
ui8 battleGetSiegeLevel();
/// returns hero corresponding to given side (0 - attacker, 1 - defender)
const CGHeroInstance * battleGetFightingHero(ui8 side) const;
/// checks if given stack has distance penalty
si8 battleHasDistancePenalty(const CStack * stack, THex destHex);
/// checks if given stack has wall penalty
si8 battleHasWallPenalty(const CStack * stack, THex destHex);
/// checks if teleportation of given stack to given position can take place
si8 battleCanTeleportTo(const CStack * stack, THex destHex, int telportLevel);
/// returns tactic distance for calling player or 0 if player is not in tactic phase
si8 battleGetTacticDist();
/// return side of player in battle (attacker/defender)
ui8 battleGetMySide();
//convenience methods using the ones above
TStacks battleGetAllStacks() //returns all stacks, alive or dead or undead or mechanical :)
/// returns all stacks, alive or dead or undead or mechanical :)
TStacks battleGetAllStacks()
{
return battleGetStacks(MINE_AND_ENEMY, false);
}
@ -191,7 +248,9 @@ public:
const CGTownInstance * getTownInfo(int val, bool mode)const; //mode = 0 -> val = player town serial; mode = 1 -> val = object id (serial)
std::vector<const CGHeroInstance *> getAvailableHeroes(const CGObjectInstance * townOrTavern) const; //heroes that can be recruited
std::string getTavernGossip(const CGObjectInstance * townOrTavern) const;
int canBuildStructure(const CGTownInstance *t, int ID);//// 0 - no more than one capitol, 1 - lack of water, 2 - forbidden, 3 - Add another level to Mage Guild, 4 - already built, 5 - cannot build, 6 - cannot afford, 7 - build, 8 - lack of requirements
/// 0 - no more than one capitol, 1 - lack of water, 2 - forbidden, 3 - Add another level to Mage Guild, 4 - already built, 5 - cannot build, 6 - cannot afford, 7 - build, 8 - lack of requirements
int canBuildStructure(const CGTownInstance *t, int ID);/
std::set<int> getBuildingRequiments(const CGTownInstance *t, int ID);
virtual bool getTownInfo(const CGObjectInstance *town, InfoAboutTown &dest) const;
const CTown *getNativeTown(int color) const;
@ -314,6 +373,8 @@ public:
};
/// Interface class for handling general game logic and actions
class DLL_EXPORT IGameCallback : public CPrivilagedInfoCallback, public IGameEventCallback
{
public:

View File

@ -35,38 +35,68 @@ struct SetStackEffect;
class DLL_EXPORT IBattleEventsReceiver
{
public:
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 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())
/// occurs AFTER every action taken by any stack or by the hero
virtual void actionFinished(const BattleAction *action){};
/// occurs BEFORE every action taken by any stack or by the hero
virtual void actionStarted(const BattleAction *action){};
/// called when stack is performing attack
virtual void battleAttack(const BattleAttack *ba){};
/// called when stack receives damage (after battleAttack())
virtual void battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa){};
virtual void battleEnd(const BattleResult *br){};
virtual void battleNewRoundFirst(int round){}; //called at the beginning of each turn before changes are applied;
virtual void battleNewRound(int round){}; //called at the beginning of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
/// called at the beginning of each turn before changes are applied;
virtual void battleNewRoundFirst(int round){};
/// called at the beginning of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
virtual void battleNewRound(int round){};
/// called when stack moves between tiles; dest is vector of tiles traversed
virtual void battleStackMoved(const CStack * stack, std::vector<THex> dest, int distance){};
/// called each time after spell is cast
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 battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, bool tentHeal, si32 lifeDrainFrom){}; //called when stacks are healed / resurrected first element of pair - stack id, second - healed hp
virtual void battleNewStackAppeared(const CStack * stack){}; //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
/// called when a specific effect is set to stacks
virtual void battleStacksEffectsSet(const SetStackEffect & sse){};
/// called by engine when battle starts; side=0 - left, side=1 - right
virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side){};
/// called when stacks are healed / resurrected first element of pair - stack id, second - healed hp
virtual void battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, bool tentHeal, si32 lifeDrainFrom){};
/// not called at the beginning of a battle or by resurrection; called eg. when elemental is summoned
virtual void battleNewStackAppeared(const CStack * stack){};
/// called when a certain set of obstacles is removed from batlefield; IDs of them are given
virtual void battleObstaclesRemoved(const std::set<si32> & removedObstacles){};
/// called when catapult makes an attack
virtual void battleCatapultAttacked(const CatapultAttack & ca){};
/// called when certain stack is completely removed from battlefield
virtual void battleStacksRemoved(const BattleStacksRemoved & bsr){};
};
class DLL_EXPORT IGameEventsReceiver
{
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
virtual void battleResultsApplied(){}; //called when all effects of last battle are applied
virtual void battleResultsApplied(){}; /// called when all effects of last battle are applied
//garrison operations
virtual void stackChagedCount(const StackLocation &location, const TQuantity &change, bool isAbsolute){}; //if absolute, change is the new count; otherwise count was modified by adding change
virtual void stackChangedType(const StackLocation &location, const CCreature &newType){}; //used eg. when upgrading creatures
virtual void stacksErased(const StackLocation &location){}; //stack removed from previously filled slot
virtual void stackChagedCount(const StackLocation &location, const TQuantity &change, bool isAbsolute){}; /// if absolute, change is the new count; otherwise count was modified by adding change
virtual void stackChangedType(const StackLocation &location, const CCreature &newType){}; /// used eg. when upgrading creatures
virtual void stacksErased(const StackLocation &location){}; /// stack removed from previously filled slot
virtual void stacksSwapped(const StackLocation &loc1, const StackLocation &loc2){};
virtual void newStackInserted(const StackLocation &location, const CStackInstance &stack){}; //new stack inserted at given (previously empty position)
virtual void stacksRebalanced(const StackLocation &src, const StackLocation &dst, TQuantity count){}; //moves creatures from src stack to dst slot, may be used for merging/splittint/moving stacks
virtual void newStackInserted(const StackLocation &location, const CStackInstance &stack){}; /// new stack inserted at given (previously empty position)
virtual void stacksRebalanced(const StackLocation &src, const StackLocation &dst, TQuantity count){}; /// moves creatures from src stack to dst slot, may be used for merging/splittint/moving stacks
//virtual void garrisonChanged(const CGObjectInstance * obj){};
//artifacts operations
@ -82,33 +112,33 @@ public:
virtual void heroMoved(const TryMoveHero & details){};
virtual void heroPrimarySkillChanged(const CGHeroInstance * hero, int which, si64 val){};
virtual void heroSecondarySkillChanged(const CGHeroInstance * hero, int which, int val){};
virtual void heroManaPointsChanged(const CGHeroInstance * hero){} //not called at the beginning of turn and after spell casts
virtual void heroMovePointsChanged(const CGHeroInstance * hero){} //not called at the beginning of turn and after movement
virtual void heroManaPointsChanged(const CGHeroInstance * hero){} /// not called at the beginning of turn and after spell casts
virtual void heroMovePointsChanged(const CGHeroInstance * hero){} /// not called at the beginning of turn and after movement
virtual void heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * town){};
virtual void receivedResource(int type, int val){};
virtual void showInfoDialog(const std::string &text, const std::vector<Component*> &components, int soundID){};
virtual void showRecruitmentDialog(const CGDwelling *dwelling, const CArmedInstance *dst, int level){}
virtual void showShipyardDialog(const IShipyard *obj){} //obj may be town or shipyard; state: 0 - can buid, 1 - lack of resources, 2 - dest tile is blocked, 3 - no water
virtual void showShipyardDialog(const IShipyard *obj){} /// obj may be town or shipyard; state: 0 - can buid, 1 - lack of resources, 2 - dest tile is blocked, 3 - no water
virtual void showPuzzleMap(){};
virtual void showMarketWindow(const IMarket *market, const CGHeroInstance *visitor){};
virtual void showUniversityWindow(const IMarket *market, const CGHeroInstance *visitor){};
virtual void showHillFortWindow(const CGObjectInstance *object, const CGHeroInstance *visitor){};
virtual void showTavernWindow(const CGObjectInstance *townOrTavern){};
virtual void advmapSpellCast(const CGHeroInstance * caster, int spellID){}; //called when a hero casts a spell
virtual void advmapSpellCast(const CGHeroInstance * caster, int spellID){}; /// called when a hero casts a spell
virtual void tileHidden(const boost::unordered_set<int3, ShashInt3> &pos){};
virtual void tileRevealed(const boost::unordered_set<int3, ShashInt3> &pos){};
virtual void newObject(const CGObjectInstance * obj){}; //eg. ship built in shipyard
virtual void availableArtifactsChanged(const CGBlackMarket *bm = NULL){}; //bm may be NULL, then artifacts are changed in the global pool (used by merchants in towns)
virtual void newObject(const CGObjectInstance * obj){}; /// eg. ship built in shipyard
virtual void availableArtifactsChanged(const CGBlackMarket *bm = NULL){}; /// bm may be NULL, then artifacts are changed in the global pool (used by merchants in towns)
virtual void centerView (int3 pos, int focusTime){};
virtual void availableCreaturesChanged(const CGDwelling *town){};
virtual void heroBonusChanged(const CGHeroInstance *hero, const Bonus &bonus, bool gain){};//if gain hero received bonus, else he lost it
virtual void playerBonusChanged(const Bonus &bonus, bool gain){};//if gain hero received bonus, else he lost it
virtual void heroBonusChanged(const CGHeroInstance *hero, const Bonus &bonus, bool gain){};/// if gain hero received bonus, else he lost it
virtual void playerBonusChanged(const Bonus &bonus, bool gain){};/// if gain hero received bonus, else he lost it
virtual void requestRealized(PackageApplied *pa){};
virtual void heroExchangeStarted(si32 hero1, si32 hero2){};
virtual void objectPropertyChanged(const SetObjectProperty * sop){}; //eg. mine has been flagged
virtual void objectRemoved(const CGObjectInstance *obj){}; //eg. collected resource, picked artifact, beaten hero
virtual void playerBlocked(int reason){}; //reason: 0 - upcoming battle
virtual void gameOver(ui8 player, bool victory){}; //player lost or won the game
virtual void objectPropertyChanged(const SetObjectProperty * sop){}; /// eg. mine has been flagged
virtual void objectRemoved(const CGObjectInstance *obj){}; /// eg. collected resource, picked artifact, beaten hero
virtual void playerBlocked(int reason){}; /// reason: 0 - upcoming battle
virtual void gameOver(ui8 player, bool victory){}; /// player lost or won the game
virtual void playerStartsTurn(ui8 player){};
};

View File

@ -281,6 +281,9 @@
<ClInclude Include="VCMI_Lib.h" />
<ClInclude Include="VCMIDirs.h" />
</ItemGroup>
<ItemGroup>
<None Include="ClassDiagram1.cd" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>

View File

@ -644,16 +644,24 @@ void CGameHandler::applyBattleEffects(BattleAttack &bat, const CStack *att, cons
}
void CGameHandler::disqualifyPlayer(int side)
{
if(!battleResult.get())
{
tlog0 << "The side " << (int)side << " will be disqualified!\n";
boost::unique_lock<boost::shared_mutex> lock(*gs->mx);
setBattleResult(3, !side);
battleMadeAction.setn(true);
}
else
{
tlog0 << "The side " << side << " won't be disqualified since battle is over.\n";
}
}
void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
{
setThreadName(-1, "CGameHandler::handleConnection");
int player = players.size() ? *players.begin() : -1;
setThreadName(-1, "CGameHandler::handleConnection" + boost::lexical_cast<std::string>(player));
srand(time(NULL));
CPack *pack = NULL;
@ -663,7 +671,7 @@ void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
{
if(gs->curB && gs->initialOpts->mode == StartInfo::DUEL)
{
onException = boost::bind(&CGameHandler::disqualifyPlayer, this, *players.begin());
onException = boost::bind(&CGameHandler::disqualifyPlayer, this, player);
}
while(1)//server should never shut connection first //was: while(!end2)
@ -673,7 +681,7 @@ void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
int packType = typeList.getTypeID(pack); //get the id of type
if(packType == typeList.getTypeID<CloseServer>())
{
tlog0 << "Ending listening thread for side " << *players.begin() << std::endl;
tlog0 << "Ending listening thread for side " << player << std::endl;
break;
}
@ -716,6 +724,7 @@ void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
}
catch(boost::system::system_error &e) //for boost errors just log, not crash - probably client shut down connection
{
tlog2 << "Exception when handling connection for player " << player << std::endl;
boost::unique_lock<boost::recursive_mutex> lock(gsm);
if(gs->scenarioOps->mode != StartInfo::DUEL)
{
@ -725,7 +734,15 @@ void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
end2 = true;
if(onException) onException();
}
HANDLE_EXCEPTIONC(boost::unique_lock<boost::recursive_mutex> lock(gsm);end2 = true; if(onException) {onException();return;});
HANDLE_EXCEPTIONC(
tlog2 << "Unknown exception when handling connection for player " << player << std::endl;
boost::unique_lock<boost::recursive_mutex> lock(gsm);
end2 = true;
if(onException)
{
onException();
return;
});
tlog1 << "Ended handling connection\n";
}

View File

@ -523,6 +523,7 @@ bool memViolated(const int pid, const int refpid, const int limit) {
void memoryMonitor(int lAIpid, int rAIpid, int refPid)
{
setThreadName(-1, "memoryMonitor");
const int MAX_MEM = 20000; //in blocks (of, I hope, 4096 B)
monitringRes = 2;
tlog0 << "Monitor is activated\n";