1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-03-17 20:58:07 +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 "../../lib/CCreatureHandler.h"
#include <algorithm> #include <algorithm>
//#include <boost/thread.hpp> //#include <boost/thread.hpp>
#include "../../lib/CHeroHandler.h"
CBattleCallback * cbc; CBattleCallback * cbc;
@ -204,16 +205,8 @@ void CStupidAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2
{ {
print("battleStart called"); print("battleStart called");
side = Side; side = Side;
TStacks myStacks = cb->battleGetStacks(CBattleCallback::ONLY_MINE); printOpeningReport();
std::cout << "My side: " << side << std::endl
<< "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%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) 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; CBattleCallback *cb;
void print(const std::string &text) const; void print(const std::string &text) const;
void printOpeningReport();
public: public:
CStupidAI(void); CStupidAI(void);
~CStupidAI(void); ~CStupidAI(void);

View File

@ -58,13 +58,13 @@ struct CheckTime
//all ms //all ms
const int PROCESS_INFO_TIME = 5; 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 MEASURE_MARGIN = 1;
const int HANGUP_TIME = 50; const int HANGUP_TIME = 50;
const int STARTUP_TIME = 100; const int STARTUP_TIME = 100;
void postInfoCall(int timeUsed); void postInfoCall(int timeUsed);
void postDecisionCall(int timeUsed); void postDecisionCall(int timeUsed, const std::string &text = "AI was thinking over an action");
struct Bomb 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) if(timeUsed > MAKE_DECIDION_TIME + MEASURE_MARGIN)
{ {
tlog1 << "That's too long! AI is disqualified!\n"; tlog1 << "That's too long! AI is disqualified!\n";

View File

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

View File

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

View File

@ -75,9 +75,10 @@ struct DLL_EXPORT BattleInfo : public CBonusSystemNode
h & static_cast<CBonusSystemNode&>(*this); h & static_cast<CBonusSystemNode&>(*this);
} }
////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
//void getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root = NULL) const; //void getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root = NULL) const;
////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
const CStack * getNextStack() const; //which stack will have turn after current one 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 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 class DLL_EXPORT CStack : public CBonusSystemNode, public CStackBasicDescriptor
{ {
public: 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; 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 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) /// HP of first creature in stack
ui8 attackerOwned; //if true, this stack is owned by attakcer (this one from left hand side of battle) ui32 firstHPleft;
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) /// owner - player colour (255 for neutrals), slot - position in garrison (may be 255 for neutrals/called creatures)
si16 shots; //how many shots left ui8 owner, slot;
ui8 casts; //how many casts left
/// 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; std::set<ECombatInfo> state;
//overrides
const CCreature* getCreature() const {return type;} const CCreature* getCreature() const {return type;}
CStack(const CStackInstance *base, int O, int I, bool AO, int S); //c-tor /// c-tor
CStack(const CStackBasicDescriptor *stack, int O, int I, bool AO, int S = 255); //c-tor CStack(const CStackInstance *base, int O, int I, bool AO, int S);
CStack(); //c-tor
/// c-tor
CStack(const CStackBasicDescriptor *stack, int O, int I, bool AO, int S = 255);
/// c-tor
CStack();
~CStack(); ~CStack();
std::string nodeName() const OVERRIDE; std::string nodeName() const OVERRIDE;
void init(); //set initial (invalid) values /// set initial (invalid) values
void postInit(); //used to finish initialization when inheriting creature parameters is working void init();
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 /// used to finish initialization when inheriting creature parameters is working
bool willMove(int turn = 0) const; //if stack has remaining move this turn void postInit();
bool ableToRetaliate() const; //if stack can retaliate after attacked
bool moved(int turn = 0) const; //if stack was already moved this turn /// effect id (SP)
bool canMove(int turn = 0) const; //if stack can move const Bonus * getEffect(ui16 id, int turn = 0) const;
ui32 Speed(int turn = 0) const; //get speed of creature with all modificators
/// 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); 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 /// 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 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) 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); 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; 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) 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); return vstd::contains(state,ALIVE);
} }

View File

@ -19,11 +19,19 @@ public:
class DLL_EXPORT IBattleCallback class DLL_EXPORT IBattleCallback
{ {
public: public:
bool waitTillRealize; //if true, request functions will return after they are realized by server /// 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! 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 //battle
virtual int battleMakeAction(BattleAction* action)=0;//for casting spells by hero - DO NOT use it for moving active stack /// for casting spells by hero - DO NOT use it for moving active stack
virtual bool battleMakeTacticAction(BattleAction * action) =0; // performs tactic phase actions virtual int battleMakeAction(BattleAction* action)=0;
/// performs tactic phase actions
virtual bool battleMakeTacticAction(BattleAction * action) =0;
}; };
class DLL_EXPORT CBattleCallback : public IBattleCallback, public CBattleInfoCallback class DLL_EXPORT CBattleCallback : public IBattleCallback, public CBattleInfoCallback
@ -35,8 +43,12 @@ protected:
public: public:
CBattleCallback(CGameState *GS, int Player, IConnectionHandler *C); 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 /// for casting spells by hero - DO NOT use it for moving active stack
bool battleMakeTacticAction(BattleAction * action) OVERRIDE; // performs tactic phase actions int battleMakeAction(BattleAction* action) OVERRIDE;
/// performs tactic phase actions
bool battleMakeTacticAction(BattleAction * action) OVERRIDE;
friend class CCallback; friend class CCallback;
friend class CClient; friend class CClient;

View File

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

View File

@ -33,6 +33,7 @@
#include "../lib/JsonNode.h" #include "../lib/JsonNode.h"
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
#include "BattleAction.h" #include "BattleAction.h"
//#include <windows.h>
boost::rand48 ran; boost::rand48 ran;
class CGObjectInstance; class CGObjectInstance;
@ -967,10 +968,14 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed )
CArmedInstance *obj = NULL; CArmedInstance *obj = NULL;
if(dp.sides[i].heroId >= 0) if(dp.sides[i].heroId >= 0)
{ {
const DuelParameters::SideSettings &ss = dp.sides[i];
CGHeroInstance *h = new CGHeroInstance(); CGHeroInstance *h = new CGHeroInstance();
armies[i] = heroes[i] = h; armies[i] = heroes[i] = h;
obj = 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); h->initHero(h->subID);
obj->initObj(); obj->initObj();
} }
@ -2812,7 +2817,23 @@ DuelParameters DuelParameters::fromJSON(const std::string &fname)
i++; i++;
} }
if(n["heroid"].getType() == JsonNode::DATA_FLOAT)
ss.heroId = n["heroid"].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) if(ss.heroId != -1)
BOOST_FOREACH(const JsonNode &spell, n["spells"].Vector()) BOOST_FOREACH(const JsonNode &spell, n["spells"].Vector())
ss.spells.insert(spell.Float()); ss.spells.insert(spell.Float());

View File

@ -297,12 +297,13 @@ struct DLL_EXPORT DuelParameters
} stacks[ARMY_SIZE]; } stacks[ARMY_SIZE];
si32 heroId; //-1 if none si32 heroId; //-1 if none
std::vector<si32> heroPrimSkills; //may be empty
std::set<si32> spells; std::set<si32> spells;
SideSettings(); SideSettings();
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
h & stacks & heroId & spells; h & stacks & heroId & heroPrimSkills & spells;
} }
} sides[2]; } 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) void setThreadName(long threadID, const std::string &name)
{ {
names.push_back(name);
#ifdef _WIN32 #ifdef _WIN32
//follows http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx //follows http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
const DWORD MS_VC_EXCEPTION=0x406D1388; const DWORD MS_VC_EXCEPTION=0x406D1388;
@ -65,10 +67,12 @@ void setThreadName(long threadID, const std::string &name)
#pragma pack(pop) #pragma pack(pop)
THREADNAME_INFO info; THREADNAME_INFO info;
info.dwType = 0x1000; info.dwType = 0x1000;
info.szName = name.c_str(); info.szName = names.back().c_str();
info.dwThreadID = threadID; info.dwThreadID = threadID;
info.dwFlags = 0; info.dwFlags = 0;
tlog5 << "Thread " << GetCurrentThreadId() << " will be known as " << name << std::endl;
__try __try
{ {
RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info ); 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 ONLY_MINE, ONLY_ENEMY, MINE_AND_ENEMY
}; };
//battle /// 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(); // 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 int battleGetBattlefieldType();
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 /// returns bitfield
THex battleGetPos(int stack); //returns position (tile ID) of stack int battleGetObstaclesAtTile(THex tile);
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 /// returns all obstacles on the battlefield
void battleGetStackCountOutsideHexes(bool *ac); // returns hexes which when in front of a stack cause us to move the amount box back std::vector<CObstacleInstance> battleGetAllObstacles();
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] /// 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); 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 /// returns true if unit with id ID can shoot to dest
bool battleCanCastSpell(); //returns true, if caller can cast a spell bool battleCanShoot(const CStack * stack, THex dest);
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 /// returns true, if caller can cast a spell
int battleGetSurrenderCost(); //returns cost of surrendering battle, -1 if surrendering is not possible bool battleCanCastSpell();
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 /// determines if given spell can be casted (and returns problem description)
int battleGetWallUnderHex(THex hex); //returns part of destructible wall / gate / keep under given hex or -1 if not found SpellCasting::ESpellCastProblem battleCanCastThisSpell(const CSpell * spell);
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 /// returns true if caller can flee from the battle
const CGHeroInstance * battleGetFightingHero(ui8 side) const; //returns hero corresponding to given side (0 - attacker, 1 - defender) bool battleCanFlee();
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 /// returns cost of surrendering battle, -1 if surrendering is not possible
si8 battleCanTeleportTo(const CStack * stack, THex destHex, int telportLevel); //checks if teleportation of given stack to given position can take place int battleGetSurrenderCost();
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 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 //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); 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) 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::vector<const CGHeroInstance *> getAvailableHeroes(const CGObjectInstance * townOrTavern) const; //heroes that can be recruited
std::string getTavernGossip(const CGObjectInstance * townOrTavern) const; 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); std::set<int> getBuildingRequiments(const CGTownInstance *t, int ID);
virtual bool getTownInfo(const CGObjectInstance *town, InfoAboutTown &dest) const; virtual bool getTownInfo(const CGObjectInstance *town, InfoAboutTown &dest) const;
const CTown *getNativeTown(int color) const; const CTown *getNativeTown(int color) const;
@ -314,6 +373,8 @@ public:
}; };
/// Interface class for handling general game logic and actions /// Interface class for handling general game logic and actions
class DLL_EXPORT IGameCallback : public CPrivilagedInfoCallback, public IGameEventCallback class DLL_EXPORT IGameCallback : public CPrivilagedInfoCallback, public IGameEventCallback
{ {
public: public:

View File

@ -35,38 +35,68 @@ struct SetStackEffect;
class DLL_EXPORT IBattleEventsReceiver class DLL_EXPORT IBattleEventsReceiver
{ {
public: public:
virtual void actionFinished(const BattleAction *action){};//occurs AFTER every action taken by any stack or by the hero /// 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 actionFinished(const BattleAction *action){};
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 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 battleEnd(const BattleResult *br){};
virtual void battleNewRoundFirst(int round){}; //called at the beginning of each turn before changes are applied; /// 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 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){}; 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 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 /// called when a specific effect is set to stacks
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 battleStacksEffectsSet(const SetStackEffect & sse){};
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 /// called by engine when battle starts; side=0 - left, side=1 - right
virtual void battleCatapultAttacked(const CatapultAttack & ca){}; //called when catapult makes an attack virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side){};
virtual void battleStacksRemoved(const BattleStacksRemoved & bsr){}; //called when certain stack is completely removed from battlefield
/// 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 class DLL_EXPORT IGameEventsReceiver
{ {
public: 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 //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 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 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 stacksErased(const StackLocation &location){}; /// stack removed from previously filled slot
virtual void stacksSwapped(const StackLocation &loc1, const StackLocation &loc2){}; 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 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 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){}; //virtual void garrisonChanged(const CGObjectInstance * obj){};
//artifacts operations //artifacts operations
@ -82,33 +112,33 @@ public:
virtual void heroMoved(const TryMoveHero & details){}; virtual void heroMoved(const TryMoveHero & details){};
virtual void heroPrimarySkillChanged(const CGHeroInstance * hero, int which, si64 val){}; virtual void heroPrimarySkillChanged(const CGHeroInstance * hero, int which, si64 val){};
virtual void heroSecondarySkillChanged(const CGHeroInstance * hero, int which, int 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 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 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 heroVisitsTown(const CGHeroInstance* hero, const CGTownInstance * town){};
virtual void receivedResource(int type, int val){}; virtual void receivedResource(int type, int val){};
virtual void showInfoDialog(const std::string &text, const std::vector<Component*> &components, int soundID){}; 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 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 showPuzzleMap(){};
virtual void showMarketWindow(const IMarket *market, const CGHeroInstance *visitor){}; virtual void showMarketWindow(const IMarket *market, const CGHeroInstance *visitor){};
virtual void showUniversityWindow(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 showHillFortWindow(const CGObjectInstance *object, const CGHeroInstance *visitor){};
virtual void showTavernWindow(const CGObjectInstance *townOrTavern){}; 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 tileHidden(const boost::unordered_set<int3, ShashInt3> &pos){};
virtual void tileRevealed(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 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 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 centerView (int3 pos, int focusTime){};
virtual void availableCreaturesChanged(const CGDwelling *town){}; 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 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 playerBonusChanged(const Bonus &bonus, bool gain){};/// if gain hero received bonus, else he lost it
virtual void requestRealized(PackageApplied *pa){}; virtual void requestRealized(PackageApplied *pa){};
virtual void heroExchangeStarted(si32 hero1, si32 hero2){}; virtual void heroExchangeStarted(si32 hero1, si32 hero2){};
virtual void objectPropertyChanged(const SetObjectProperty * sop){}; //eg. mine has been flagged 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 objectRemoved(const CGObjectInstance *obj){}; /// eg. collected resource, picked artifact, beaten hero
virtual void playerBlocked(int reason){}; //reason: 0 - upcoming battle virtual void playerBlocked(int reason){}; /// reason: 0 - upcoming battle
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 playerStartsTurn(ui8 player){}; virtual void playerStartsTurn(ui8 player){};
}; };

View File

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

View File

@ -644,16 +644,24 @@ void CGameHandler::applyBattleEffects(BattleAttack &bat, const CStack *att, cons
} }
void CGameHandler::disqualifyPlayer(int side) void CGameHandler::disqualifyPlayer(int side)
{
if(!battleResult.get())
{ {
tlog0 << "The side " << (int)side << " will be disqualified!\n"; tlog0 << "The side " << (int)side << " will be disqualified!\n";
boost::unique_lock<boost::shared_mutex> lock(*gs->mx); boost::unique_lock<boost::shared_mutex> lock(*gs->mx);
setBattleResult(3, !side); setBattleResult(3, !side);
battleMadeAction.setn(true); 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) 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)); srand(time(NULL));
CPack *pack = 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) 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) 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 int packType = typeList.getTypeID(pack); //get the id of type
if(packType == typeList.getTypeID<CloseServer>()) 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; 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 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); boost::unique_lock<boost::recursive_mutex> lock(gsm);
if(gs->scenarioOps->mode != StartInfo::DUEL) if(gs->scenarioOps->mode != StartInfo::DUEL)
{ {
@ -725,7 +734,15 @@ void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
end2 = true; end2 = true;
if(onException) onException(); 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"; 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) void memoryMonitor(int lAIpid, int rAIpid, int refPid)
{ {
setThreadName(-1, "memoryMonitor");
const int MAX_MEM = 20000; //in blocks (of, I hope, 4096 B) const int MAX_MEM = 20000; //in blocks (of, I hope, 4096 B)
monitringRes = 2; monitringRes = 2;
tlog0 << "Monitor is activated\n"; tlog0 << "Monitor is activated\n";