mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-02 00:10:22 +02:00
Big change: Introduced new mechanism to handle queries. It should not cause any visible changes ATM apart from fixing several long-standing bugs realted to handling post-visit/battle/levelup callback, including infamous creature bank issues: #955, #1053, #1063, #1191. Needs testing.
Minor changes: * default log level set to trace * LOG_TRACE raii guardian lifetime will last till the end of block * compile fixes * minor refactorings
This commit is contained in:
parent
1fca335a2c
commit
e8354908c3
@ -43,24 +43,6 @@ struct SetGlobalState
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Container>
|
||||
typename Container::value_type backOrNull(const Container &c) //returns last element of container or NULL if it is empty (to be used with containers of pointers)
|
||||
{
|
||||
if(c.size())
|
||||
return c.back();
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
typename Container::value_type frontOrNull(const Container &c) //returns first element of container or NULL if it is empty (to be used with containers of pointers)
|
||||
{
|
||||
if(c.size())
|
||||
return c.front();
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
#define SET_GLOBAL_STATE(ai) SetGlobalState _hlpSetState(ai);
|
||||
|
||||
@ -793,7 +775,7 @@ void VCAI::heroManaPointsChanged(const CGHeroInstance * hero)
|
||||
|
||||
void VCAI::heroSecondarySkillChanged(const CGHeroInstance * hero, int which, int val)
|
||||
{
|
||||
LOG_TRACE_PARAMS(logAi, "which '%', val '%'", which % val);
|
||||
LOG_TRACE_PARAMS(logAi, "which '%d', val '%d'", which % val);
|
||||
NET_EVENT_HANDLER;
|
||||
}
|
||||
|
||||
@ -2579,6 +2561,7 @@ AIStatus::~AIStatus()
|
||||
void AIStatus::setBattle(BattleState BS)
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(mx);
|
||||
LOG_TRACE_PARAMS(logAi, "battle state=%d", (int)BS);
|
||||
battle = BS;
|
||||
cv.notify_all();
|
||||
}
|
||||
|
18
Global.h
18
Global.h
@ -568,6 +568,24 @@ namespace vstd
|
||||
{
|
||||
obj = (T)(((int)obj) + change);
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
typename Container::value_type backOrNull(const Container &c) //returns last element of container or NULL if it is empty (to be used with containers of pointers)
|
||||
{
|
||||
if(c.size())
|
||||
return c.back();
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
typename Container::value_type frontOrNull(const Container &c) //returns first element of container or NULL if it is empty (to be used with containers of pointers)
|
||||
{
|
||||
if(c.size())
|
||||
return c.front();
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
using vstd::operator-=;
|
||||
using vstd::make_unique;
|
||||
|
@ -176,7 +176,9 @@ static void prog_help(const po::options_description &opts)
|
||||
void OSX_checkForUpdates();
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#ifdef _WIN32
|
||||
int wmain(int argc, wchar_t* argv[])
|
||||
#elif defined(__APPLE__)
|
||||
int SDL_main(int argc, char *argv[])
|
||||
#else
|
||||
int main(int argc, char** argv)
|
||||
|
@ -230,10 +230,10 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details)
|
||||
if(LOCPLINT != this)
|
||||
return;
|
||||
|
||||
const CGHeroInstance * ho = cb->getHero(details.id); //object representing this hero
|
||||
const CGHeroInstance * hero = cb->getHero(details.id); //object representing this hero
|
||||
int3 hp = details.start;
|
||||
|
||||
if(!ho)
|
||||
if(!hero)
|
||||
{
|
||||
//AI hero left the visible area (we can't obtain info)
|
||||
//TODO very evil workaround -> retreive pointer to hero so we could animate it
|
||||
@ -241,25 +241,25 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details)
|
||||
const TerrainTile2 &tile = CGI->mh->ttiles[hp.x-1][hp.y][hp.z];
|
||||
for(int i = 0; i < tile.objects.size(); i++)
|
||||
if(tile.objects[i].first->id == details.id)
|
||||
ho = dynamic_cast<const CGHeroInstance *>(tile.objects[i].first);
|
||||
hero = dynamic_cast<const CGHeroInstance *>(tile.objects[i].first);
|
||||
|
||||
if(!ho) //still nothing...
|
||||
if(!hero) //still nothing...
|
||||
return;
|
||||
}
|
||||
|
||||
adventureInt->centerOn(ho); //actualizing screen pos
|
||||
adventureInt->centerOn(hero); //actualizing screen pos
|
||||
adventureInt->minimap.redraw();
|
||||
adventureInt->heroList.redraw();
|
||||
|
||||
bool directlyAttackingCreature =
|
||||
CGI->mh->map->isInTheMap(details.attackedFrom)
|
||||
details.attackedFrom
|
||||
&& adventureInt->terrain.currentPath //in case if movement has been canceled in the meantime and path was already erased
|
||||
&& adventureInt->terrain.currentPath->nodes.size() == 3;//FIXME should be 2 but works nevertheless...
|
||||
|
||||
if(makingTurn && ho->tempOwner == playerID) //we are moving our hero - we may need to update assigned path
|
||||
if(makingTurn && hero->tempOwner == playerID) //we are moving our hero - we may need to update assigned path
|
||||
{
|
||||
//We may need to change music - select new track, music handler will change it if needed
|
||||
CCS->musich->playMusicFromSet("terrain", LOCPLINT->cb->getTile(ho->visitablePos())->terType, true);
|
||||
CCS->musich->playMusicFromSet("terrain", LOCPLINT->cb->getTile(hero->visitablePos())->terType, true);
|
||||
|
||||
if(details.result == TryMoveHero::TELEPORTATION)
|
||||
{
|
||||
@ -272,42 +272,42 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details)
|
||||
&& (nodesIt-1)->coord == CGHeroInstance::convertPosition(details.end, false))
|
||||
{
|
||||
//path was between entrance and exit of teleport -> OK, erase node as usual
|
||||
removeLastNodeFromPath(ho);
|
||||
removeLastNodeFromPath(hero);
|
||||
}
|
||||
else
|
||||
{
|
||||
//teleport was not along current path, it'll now be invalid (hero is somewhere else)
|
||||
eraseCurrentPathOf(ho);
|
||||
eraseCurrentPathOf(hero);
|
||||
|
||||
}
|
||||
}
|
||||
adventureInt->heroList.update(ho);
|
||||
adventureInt->heroList.update(hero);
|
||||
return; //teleport - no fancy moving animation
|
||||
//TODO: smooth disappear / appear effect
|
||||
}
|
||||
|
||||
if (ho->pos != details.end //hero didn't change tile but visit succeeded
|
||||
if (hero->pos != details.end //hero didn't change tile but visit succeeded
|
||||
|| directlyAttackingCreature) // or creature was attacked from endangering tile.
|
||||
{
|
||||
eraseCurrentPathOf(ho, false);
|
||||
eraseCurrentPathOf(hero, false);
|
||||
}
|
||||
else if(adventureInt->terrain.currentPath && ho->pos == details.end) //&& hero is moving
|
||||
else if(adventureInt->terrain.currentPath && hero->pos == details.end) //&& hero is moving
|
||||
{
|
||||
if(details.start != details.end) //so we don't touch path when revisiting with spacebar
|
||||
removeLastNodeFromPath(ho);
|
||||
removeLastNodeFromPath(hero);
|
||||
}
|
||||
}
|
||||
|
||||
if (details.result != TryMoveHero::SUCCESS) //hero failed to move
|
||||
{
|
||||
ho->isStanding = true;
|
||||
hero->isStanding = true;
|
||||
stillMoveHero.setn(STOP_MOVE);
|
||||
GH.totalRedraw();
|
||||
adventureInt->heroList.update(ho);
|
||||
adventureInt->heroList.update(hero);
|
||||
return;
|
||||
}
|
||||
|
||||
initMovement(details, ho, hp);
|
||||
initMovement(details, hero, hp);
|
||||
|
||||
//first initializing done
|
||||
GH.mainFPSmng->framerateDelay(); // after first move
|
||||
@ -316,7 +316,7 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details)
|
||||
//main moving
|
||||
for(int i=1; i<32; i+=2*speed)
|
||||
{
|
||||
movementPxStep(details, i, hp, ho);
|
||||
movementPxStep(details, i, hp, hero);
|
||||
adventureInt->updateScreen = true;
|
||||
adventureInt->show(screen);
|
||||
CSDL_Ext::update(screen);
|
||||
@ -325,12 +325,12 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details)
|
||||
//main moving done
|
||||
|
||||
//finishing move
|
||||
finishMovement(details, hp, ho);
|
||||
ho->isStanding = true;
|
||||
finishMovement(details, hp, hero);
|
||||
hero->isStanding = true;
|
||||
|
||||
//move finished
|
||||
adventureInt->minimap.redraw();
|
||||
adventureInt->heroList.update(ho);
|
||||
adventureInt->heroList.update(hero);
|
||||
|
||||
//check if user cancelled movement
|
||||
{
|
||||
@ -358,14 +358,14 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details)
|
||||
// Hero attacked creature directly, set direction to face it.
|
||||
if (directlyAttackingCreature) {
|
||||
// Get direction to attacker.
|
||||
int3 posOffset = details.attackedFrom - details.end + int3(2, 1, 0);
|
||||
int3 posOffset = *details.attackedFrom - details.end + int3(2, 1, 0);
|
||||
static const ui8 dirLookup[3][3] = {
|
||||
{ 1, 2, 3 },
|
||||
{ 8, 0, 4 },
|
||||
{ 7, 6, 5 }
|
||||
};
|
||||
// FIXME: Avoid const_cast, make moveDir mutable in some other way?
|
||||
const_cast<CGHeroInstance *>(ho)->moveDir = dirLookup[posOffset.y][posOffset.x];
|
||||
const_cast<CGHeroInstance *>(hero)->moveDir = dirLookup[posOffset.y][posOffset.x];
|
||||
}
|
||||
}
|
||||
void CPlayerInterface::heroKilled(const CGHeroInstance* hero)
|
||||
|
@ -170,11 +170,12 @@ public:
|
||||
void setHoverName(const CGObjectInstance * obj, MetaString * name) OVERRIDE {};
|
||||
void changePrimSkill(const CGHeroInstance * hero, PrimarySkill::PrimarySkill which, si64 val, bool abs=false) OVERRIDE {};
|
||||
void changeSecSkill(const CGHeroInstance * hero, SecondarySkill which, int val, bool abs=false) OVERRIDE {};
|
||||
void showBlockingDialog(BlockingDialog *iw, const CFunctionList<void(ui32)> &callback) OVERRIDE {};
|
||||
ui32 showBlockingDialog(BlockingDialog *iw) OVERRIDE {return 0;}; //synchronous version of above
|
||||
|
||||
void showBlockingDialog(BlockingDialog *iw) OVERRIDE {};
|
||||
void showGarrisonDialog(ObjectInstanceID upobj, ObjectInstanceID hid, bool removableUnits, const boost::function<void()> &cb) OVERRIDE {};
|
||||
void showThievesGuildWindow(PlayerColor player, ObjectInstanceID requestingObjId) OVERRIDE {};
|
||||
void giveResource(PlayerColor player, Res::ERes which, int val) OVERRIDE {};
|
||||
virtual void giveResources(PlayerColor player, TResources resources) OVERRIDE {};
|
||||
|
||||
void giveCreatures(const CArmedInstance * objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) OVERRIDE {};
|
||||
void takeCreatures(ObjectInstanceID objid, const std::vector<CStackBasicDescriptor> &creatures) OVERRIDE {};
|
||||
@ -199,11 +200,11 @@ public:
|
||||
void stopHeroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero) OVERRIDE {};
|
||||
//void giveHeroArtifact(int artid, int hid, int position){};
|
||||
//void giveNewArtifact(int hid, int position){};
|
||||
void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, boost::function<void(BattleResult*)> cb = 0, const CGTownInstance *town = NULL) OVERRIDE {}; //use hero=NULL for no hero
|
||||
void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, boost::function<void(BattleResult*)> cb = 0, bool creatureBank = false) OVERRIDE {}; //if any of armies is hero, hero will be used
|
||||
void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, boost::function<void(BattleResult*)> cb = 0, bool creatureBank = false) OVERRIDE {}; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle
|
||||
void startBattlePrimary(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, const CGTownInstance *town = NULL) OVERRIDE {}; //use hero=NULL for no hero
|
||||
void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, bool creatureBank = false) OVERRIDE {}; //if any of armies is hero, hero will be used
|
||||
void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, bool creatureBank = false) OVERRIDE {}; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle
|
||||
void setAmount(ObjectInstanceID objid, ui32 val) OVERRIDE {};
|
||||
bool moveHero(ObjectInstanceID hid, int3 dst, ui8 instant, PlayerColor asker = PlayerColor::NEUTRAL) OVERRIDE {return false;};
|
||||
bool moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, PlayerColor asker = PlayerColor::NEUTRAL) OVERRIDE {return false;};
|
||||
void giveHeroBonus(GiveBonus * bonus) OVERRIDE {};
|
||||
void setMovePoints(SetMovePoints * smp) OVERRIDE {};
|
||||
void setManaPoints(ObjectInstanceID hid, int val) OVERRIDE {};
|
||||
|
@ -545,11 +545,10 @@ void SetObjectProperty::applyCl( CClient *cl )
|
||||
|
||||
void HeroLevelUp::applyCl( CClient *cl )
|
||||
{
|
||||
const CGHeroInstance *h = cl->getHero(heroid);
|
||||
//INTERFACE_CALL_IF_PRESENT(h->tempOwner, heroGotLevel, h, primskill, skills, id);
|
||||
if(vstd::contains(cl->playerint,h->tempOwner))
|
||||
if(vstd::contains(cl->playerint,hero->tempOwner))
|
||||
{
|
||||
cl->playerint[h->tempOwner]->heroGotLevel(h, primskill, skills, queryID);
|
||||
cl->playerint[hero->tempOwner]->heroGotLevel(hero, primskill, skills, queryID);
|
||||
}
|
||||
//else
|
||||
// cb->selectionMade(0, queryID);
|
||||
@ -557,9 +556,9 @@ void HeroLevelUp::applyCl( CClient *cl )
|
||||
|
||||
void CommanderLevelUp::applyCl( CClient *cl )
|
||||
{
|
||||
CCommanderInstance * commander = GS(cl)->getHero(heroid)->commander;
|
||||
const CCommanderInstance * commander = hero->commander;
|
||||
assert (commander);
|
||||
PlayerColor player = commander->armyObj->tempOwner;
|
||||
PlayerColor player = hero->tempOwner;
|
||||
if (commander->armyObj && vstd::contains(cl->playerint, player)) //is it possible for Commander to exist beyond armed instance?
|
||||
{
|
||||
cl->playerint[player]->commanderGotLevel(commander, skills, queryID);
|
||||
|
@ -207,7 +207,7 @@
|
||||
},
|
||||
"loggers" : {
|
||||
"type" : "array",
|
||||
"default" : [ { "domain" : "global", "level" : "info" } ],
|
||||
"default" : [ { "domain" : "global", "level" : "trace" } ],
|
||||
"items" : {
|
||||
"type" : "object",
|
||||
"additionalProperties" : false,
|
||||
|
@ -741,6 +741,11 @@ ArtBearer::ArtBearer CCommanderInstance::bearerType() const
|
||||
return ArtBearer::COMMANDER;
|
||||
}
|
||||
|
||||
bool CCommanderInstance::gainsLevel() const
|
||||
{
|
||||
return experience >= VLC->heroh->reqExp(level+1);
|
||||
}
|
||||
|
||||
CStackBasicDescriptor::CStackBasicDescriptor()
|
||||
{
|
||||
type = NULL;
|
||||
|
@ -103,6 +103,7 @@ public:
|
||||
void giveStackExp (TExpType exp);
|
||||
void levelUp ();
|
||||
|
||||
bool gainsLevel() const; //true if commander has lower level than should upon his experience
|
||||
ui64 getPower() const {return 0;};
|
||||
int getExpRank() const;
|
||||
int getLevel() const OVERRIDE;
|
||||
|
@ -3196,7 +3196,7 @@ CGPathNode::EAccessibility CPathfinder::evaluateAccessibility(const TerrainTile
|
||||
{
|
||||
BOOST_FOREACH(const CGObjectInstance *obj, tinfo->visitableObjects)
|
||||
{
|
||||
if(obj->getPassableness() & 1<<hero->tempOwner.getNum()) //special object instance specific passableness flag - overwrites other accessibility flags
|
||||
if(obj->passableFor(hero->tempOwner)) //special object instance specific passableness flag - overwrites other accessibility flags
|
||||
{
|
||||
ret = CGPathNode::ACCESSIBLE;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -113,6 +113,13 @@ public:
|
||||
virtual void newTurn() const;
|
||||
virtual void initObj(); //synchr
|
||||
virtual void setProperty(ui8 what, ui32 val);//synchr
|
||||
|
||||
//Called when queries created DURING HERO VISIT are resolved
|
||||
//First parameter is always hero that visited object and triggered the query
|
||||
virtual void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const;
|
||||
virtual void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const;
|
||||
virtual void garrisonDialogClosed(const CGHeroInstance *hero) const;
|
||||
|
||||
//unified interface, AI helpers
|
||||
virtual bool wasVisited (PlayerColor player) const;
|
||||
virtual bool wasVisited (const CGHeroInstance * h) const;
|
||||
@ -179,6 +186,7 @@ public:
|
||||
virtual ui8 getPassableness() const; //bitmap - if the bit is set the corresponding player can pass through the visitable tiles of object, even if it's blockvis; if not set - default properties from definfo are used
|
||||
virtual int3 getSightCenter() const; //"center" tile from which the sight distance is calculated
|
||||
virtual int getSightRadious() const; //sight distance (should be used if player-owned structure)
|
||||
bool passableFor(PlayerColor color) const;
|
||||
void getSightTiles(boost::unordered_set<int3, ShashInt3> &tiles) const; //returns reference to the set
|
||||
PlayerColor getOwner() const;
|
||||
void setOwner(PlayerColor ow);
|
||||
@ -396,6 +404,8 @@ public:
|
||||
CStackBasicDescriptor calculateNecromancy (const BattleResult &battleResult) const;
|
||||
void showNecromancyDialog(const CStackBasicDescriptor &raisedStack) const;
|
||||
ECanDig diggingStatus() const; //0 - can dig; 1 - lack of movement; 2 -
|
||||
std::vector<SecondarySkill> levelUpProposedSkills() const;
|
||||
bool gainsLevel() const; //true if hero has lower level than should upon his experience
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -471,10 +481,11 @@ public:
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
void newTurn() const override;
|
||||
void setProperty(ui8 what, ui32 val) override;
|
||||
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const OVERRIDE;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const OVERRIDE;
|
||||
|
||||
private:
|
||||
void heroAcceptsCreatures(const CGHeroInstance *h, ui32 answer) const;
|
||||
void fightOver(const CGHeroInstance *h, BattleResult *result) const;
|
||||
void wantsFight(const CGHeroInstance *h, ui32 answer) const;
|
||||
void heroAcceptsCreatures(const CGHeroInstance *h) const;
|
||||
};
|
||||
|
||||
|
||||
@ -482,25 +493,26 @@ class DLL_LINKAGE CGVisitableOPH : public CGObjectInstance //objects visitable o
|
||||
{
|
||||
public:
|
||||
std::set<ObjectInstanceID> visitors; //ids of heroes who have visited this obj
|
||||
si8 ttype; //tree type - used only by trees of knowledge: 0 - give level for free; 1 - take 2000 gold; 2 - take 10 gems
|
||||
TResources treePrice; //used only by trees of knowledge: empty, 2000 gold, 10 gems
|
||||
|
||||
const std::string & getHoverText() const override;
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
void initObj() override;
|
||||
bool wasVisited (const CGHeroInstance * h) const override;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const OVERRIDE;
|
||||
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<CGObjectInstance&>(*this);
|
||||
h & visitors & ttype;
|
||||
h & visitors & treePrice;
|
||||
}
|
||||
protected:
|
||||
void setPropertyDer(ui8 what, ui32 val) override;//synchr
|
||||
private:
|
||||
void onNAHeroVisit(ObjectInstanceID heroID, bool alreadyVisited) const;
|
||||
///dialog callbacks
|
||||
void treeSelected(ObjectInstanceID heroID, int resType, int resVal, TExpType expVal, ui32 result) const;
|
||||
void treeSelected(ObjectInstanceID heroID, ui32 result) const;
|
||||
void schoolSelected(ObjectInstanceID heroID, ui32 which) const;
|
||||
void arenaSelected(ObjectInstanceID heroID, int primSkill) const;
|
||||
};
|
||||
@ -662,11 +674,9 @@ public:
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
void onHeroLeave(const CGHeroInstance * h) const override;
|
||||
void initObj() override;
|
||||
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const OVERRIDE;
|
||||
protected:
|
||||
void setPropertyDer(ui8 what, ui32 val) override;
|
||||
private:
|
||||
///dialog callbacks
|
||||
void fightOver(const CGHeroInstance *h, BattleResult *result) const;
|
||||
};
|
||||
class DLL_LINKAGE CGPandoraBox : public CArmedInstance
|
||||
{
|
||||
@ -688,6 +698,8 @@ public:
|
||||
|
||||
void initObj() override;
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const OVERRIDE;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const OVERRIDE;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
@ -696,10 +708,8 @@ public:
|
||||
& abilities & abilityLevels & artifacts & spells & creatures;
|
||||
}
|
||||
protected:
|
||||
void endBattle(const CGHeroInstance *h, BattleResult *result) const;
|
||||
void giveContents(const CGHeroInstance *h, bool afterBattle) const;
|
||||
private:
|
||||
void open (const CGHeroInstance * h, ui32 accept) const;
|
||||
void getText( InfoWindow &iw, bool &afterBattle, int val, int negative, int positive, const CGHeroInstance * h ) const;
|
||||
void getText( InfoWindow &iw, bool &afterBattle, int text, const CGHeroInstance * h ) const;
|
||||
};
|
||||
@ -725,6 +735,10 @@ private:
|
||||
|
||||
class DLL_LINKAGE CGCreature : public CArmedInstance //creatures on map
|
||||
{
|
||||
enum Action {
|
||||
FIGHT = -2, FLEE = -1, JOIN_FOR_FREE = 0 //values > 0 mean gold price
|
||||
};
|
||||
|
||||
public:
|
||||
ui32 identifier; //unique code for this monster (used in missions)
|
||||
si8 character; //character of this set of creatures (0 - the most friendly, 4 - the most hostile) => on init changed to -4 (compliant) ... 10 value (savage)
|
||||
@ -735,11 +749,14 @@ public:
|
||||
bool notGrowingTeam; //if true, number of units won't grow
|
||||
ui64 temppower; //used to handle fractional stack growth for tiny stacks
|
||||
|
||||
bool refusedJoining;
|
||||
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
const std::string & getHoverText() const override;
|
||||
void initObj() override;
|
||||
void newTurn() const override;
|
||||
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const OVERRIDE;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const OVERRIDE;
|
||||
|
||||
|
||||
struct DLL_LINKAGE RestoredCreature // info about merging stacks after battle back into one
|
||||
@ -754,7 +771,8 @@ public:
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<CArmedInstance&>(*this);
|
||||
h & identifier & character & message & resources & gainedArtifact & neverFlees & notGrowingTeam & temppower & restore;
|
||||
h & identifier & character & message & resources & gainedArtifact & neverFlees & notGrowingTeam & temppower;
|
||||
h & refusedJoining & restore;
|
||||
}
|
||||
protected:
|
||||
void setPropertyDer(ui8 what, ui32 val) override;
|
||||
@ -762,7 +780,6 @@ private:
|
||||
|
||||
void fight(const CGHeroInstance *h) const;
|
||||
void flee( const CGHeroInstance * h ) const;
|
||||
void endBattle(BattleResult *result) const;
|
||||
void fleeDecision(const CGHeroInstance *h, ui32 pursue) const;
|
||||
void joinDecision(const CGHeroInstance *h, int cost, ui32 accept) const;
|
||||
|
||||
@ -815,6 +832,7 @@ public:
|
||||
const std::string & getHoverText() const override;
|
||||
void newTurn() const override;
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const OVERRIDE;
|
||||
|
||||
int checkDirection() const; //calculates the region of map where monster is placed
|
||||
void setObjToKill(); //remember creatures / heroes to kill after they are initialized
|
||||
@ -888,7 +906,7 @@ public:
|
||||
|
||||
ui8 getPassableness() const;
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
void fightOver (const CGHeroInstance *h, BattleResult *result) const;
|
||||
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const OVERRIDE;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
@ -904,8 +922,9 @@ public:
|
||||
std::string message;
|
||||
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
void fightForArt(ui32 agreed, const CGHeroInstance *h) const;
|
||||
void endBattle(BattleResult *result, const CGHeroInstance *h) const;
|
||||
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const OVERRIDE;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const OVERRIDE;
|
||||
|
||||
void pick( const CGHeroInstance * h ) const;
|
||||
void initObj() override;
|
||||
|
||||
@ -924,10 +943,10 @@ public:
|
||||
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
void initObj() override;
|
||||
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const OVERRIDE;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const OVERRIDE;
|
||||
|
||||
void collectRes(PlayerColor player) const;
|
||||
void fightForRes(ui32 agreed, const CGHeroInstance *h) const;
|
||||
void endBattle(BattleResult *result, const CGHeroInstance *h) const;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
@ -943,7 +962,7 @@ public:
|
||||
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
void initObj() override;
|
||||
void chosen(int which, ObjectInstanceID heroID) const;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const OVERRIDE;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
@ -973,11 +992,9 @@ public:
|
||||
Res::ERes producedResource;
|
||||
ui32 producedQuantity;
|
||||
|
||||
void offerLeavingGuards(const CGHeroInstance *h) const;
|
||||
void endBattle(BattleResult *result, PlayerColor attackingPlayer) const;
|
||||
void fight(ui32 agreed, const CGHeroInstance *h) const;
|
||||
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const OVERRIDE;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const OVERRIDE;
|
||||
|
||||
void flagMine(PlayerColor player) const;
|
||||
void newTurn() const override;
|
||||
@ -1125,13 +1142,12 @@ public:
|
||||
CGBorderGuard() : IQuestObject(){};
|
||||
void initObj() override;
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const OVERRIDE;
|
||||
|
||||
void getVisitText (MetaString &text, std::vector<Component> &components, bool isCustom, bool FirstVisit, const CGHeroInstance * h = NULL) const;
|
||||
void getRolloverText (MetaString &text, bool onHover) const;
|
||||
bool checkQuest (const CGHeroInstance * h) const;
|
||||
|
||||
void openGate(const CGHeroInstance *h, ui32 accept) const;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<IQuestObject&>(*this);
|
||||
@ -1184,8 +1200,7 @@ public:
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
const std::string & getHoverText() const override;
|
||||
void initObj() override;
|
||||
|
||||
void searchTomb(const CGHeroInstance *h, ui32 accept) const;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const OVERRIDE;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
@ -1210,9 +1225,8 @@ class DLL_LINKAGE CBank : public CArmedInstance
|
||||
void newTurn() const override;
|
||||
bool wasVisited (PlayerColor player) const override;
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
|
||||
virtual void fightGuards (const CGHeroInstance *h, ui32 accept) const;
|
||||
virtual void endBattle (const CGHeroInstance *h, const BattleResult *result) const;
|
||||
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const OVERRIDE;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const OVERRIDE;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
@ -1231,8 +1245,7 @@ public:
|
||||
const std::string & getHoverText() const override;
|
||||
void newTurn() const override {}; //empty, no reset
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
|
||||
void endBattle (const CGHeroInstance *h, const BattleResult *result) const override;
|
||||
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const OVERRIDE;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
@ -1270,7 +1283,7 @@ class DLL_LINKAGE CCartographer : public CPlayersVisited
|
||||
///behaviour varies depending on surface and floor
|
||||
public:
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
void buyMap (const CGHeroInstance *h, ui32 accept) const;
|
||||
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const OVERRIDE;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
|
@ -98,3 +98,8 @@ CSpell * SpellID::toSpell() const
|
||||
|
||||
//template std::ostream & operator << <ArtifactInstanceID>(std::ostream & os, BaseForID<ArtifactInstanceID> id);
|
||||
//template std::ostream & operator << <ObjectInstanceID>(std::ostream & os, BaseForID<ObjectInstanceID> id);
|
||||
|
||||
bool PlayerColor::isValidPlayer() const
|
||||
{
|
||||
return num < PLAYER_LIMIT_I;
|
||||
}
|
||||
|
@ -215,6 +215,8 @@ class PlayerColor : public BaseForID<PlayerColor, ui8>
|
||||
DLL_LINKAGE static const int PLAYER_LIMIT_I = 8; //player limit per map
|
||||
DLL_LINKAGE static const PlayerColor PLAYER_LIMIT; //player limit per map
|
||||
|
||||
DLL_LINKAGE bool isValidPlayer() const; //valid means < PLAYER_LIMIT (especially non-neutral)
|
||||
|
||||
friend class CGameInfoCallback;
|
||||
friend class CNonConstInfoCallback;
|
||||
};
|
||||
|
@ -220,11 +220,11 @@ public:
|
||||
virtual void setHoverName(const CGObjectInstance * obj, MetaString * name)=0;
|
||||
virtual void changePrimSkill(const CGHeroInstance * hero, PrimarySkill::PrimarySkill which, si64 val, bool abs=false)=0;
|
||||
virtual void changeSecSkill(const CGHeroInstance * hero, SecondarySkill which, int val, bool abs=false)=0;
|
||||
virtual void showBlockingDialog(BlockingDialog *iw, const CFunctionList<void(ui32)> &callback)=0;
|
||||
virtual ui32 showBlockingDialog(BlockingDialog *iw) =0; //synchronous version of above //TODO:
|
||||
virtual void showBlockingDialog(BlockingDialog *iw) =0;
|
||||
virtual void showGarrisonDialog(ObjectInstanceID upobj, ObjectInstanceID hid, bool removableUnits, const boost::function<void()> &cb) =0; //cb will be called when player closes garrison window
|
||||
virtual void showThievesGuildWindow(PlayerColor player, ObjectInstanceID requestingObjId) =0;
|
||||
virtual void giveResource(PlayerColor player, Res::ERes which, int val)=0;
|
||||
virtual void giveResources(PlayerColor player, TResources resources)=0;
|
||||
|
||||
virtual void giveCreatures(const CArmedInstance *objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) =0;
|
||||
virtual void takeCreatures(ObjectInstanceID objid, const std::vector<CStackBasicDescriptor> &creatures) =0;
|
||||
@ -247,11 +247,11 @@ public:
|
||||
virtual void showCompInfo(ShowInInfobox * comp)=0;
|
||||
virtual void heroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero)=0;
|
||||
virtual void stopHeroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero)=0;
|
||||
virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, boost::function<void(BattleResult*)> cb = 0, const CGTownInstance *town = NULL)=0; //use hero=NULL for no hero
|
||||
virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, boost::function<void(BattleResult*)> cb = 0, bool creatureBank = false)=0; //if any of armies is hero, hero will be used
|
||||
virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, boost::function<void(BattleResult*)> cb = 0, bool creatureBank = false)=0; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle
|
||||
virtual void startBattlePrimary(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, const CGTownInstance *town = NULL)=0; //use hero=NULL for no hero
|
||||
virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, bool creatureBank = false)=0; //if any of armies is hero, hero will be used
|
||||
virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, bool creatureBank = false)=0; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle
|
||||
virtual void setAmount(ObjectInstanceID objid, ui32 val)=0;
|
||||
virtual bool moveHero(ObjectInstanceID hid, int3 dst, ui8 instant, PlayerColor asker = PlayerColor::NEUTRAL)=0;
|
||||
virtual bool moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, PlayerColor asker = PlayerColor::NEUTRAL)=0;
|
||||
virtual void giveHeroBonus(GiveBonus * bonus)=0;
|
||||
virtual void setMovePoints(SetMovePoints * smp)=0;
|
||||
virtual void setManaPoints(ObjectInstanceID hid, int val)=0;
|
||||
|
@ -633,7 +633,7 @@ struct RemoveObject : public CPackForClient //500
|
||||
};
|
||||
struct TryMoveHero : public CPackForClient //501
|
||||
{
|
||||
TryMoveHero(){type = 501;humanKnows=false; attackedFrom = int3(-1, -1, -1);};
|
||||
TryMoveHero(){type = 501;humanKnows=false;};
|
||||
void applyFirstCl(CClient *cl);
|
||||
void applyCl(CClient *cl);
|
||||
void applyGs(CGameState *gs);
|
||||
@ -648,7 +648,7 @@ struct TryMoveHero : public CPackForClient //501
|
||||
EResult result; //uses EResult
|
||||
int3 start, end; //h3m format
|
||||
boost::unordered_set<int3, ShashInt3> fowRevealed; //revealed tiles
|
||||
int3 attackedFrom; // Set when stepping into endangered tile.
|
||||
boost::optional<int3> attackedFrom; // Set when stepping into endangered tile.
|
||||
|
||||
bool humanKnows; //used locally during applying to client
|
||||
|
||||
@ -1168,7 +1168,7 @@ struct InfoWindow : public CPackForClient //103 - displays simple info window
|
||||
namespace ObjProperty
|
||||
{
|
||||
enum {OWNER = 1, BLOCKVIS = 2, PRIMARY_STACK_COUNT = 3, VISITORS = 4, VISITED = 5, ID = 6, AVAILABLE_CREATURE = 7, SUBID = 8,
|
||||
MONSTER_COUNT = 10, MONSTER_POWER = 11, MONSTER_EXP = 12, MONSTER_RESTORE_TYPE = 13,
|
||||
MONSTER_COUNT = 10, MONSTER_POWER = 11, MONSTER_EXP = 12, MONSTER_RESTORE_TYPE = 13, MONSTER_REFUSED_JOIN,
|
||||
|
||||
//town-specific
|
||||
STRUCTURE_ADD_VISITING_HERO, STRUCTURE_CLEAR_VISITORS, STRUCTURE_ADD_GARRISONED_HERO, //changing buildings state
|
||||
@ -1216,7 +1216,7 @@ struct HeroLevelUp : public Query//2000
|
||||
void applyCl(CClient *cl);
|
||||
DLL_LINKAGE void applyGs(CGameState *gs);
|
||||
|
||||
ObjectInstanceID heroid;
|
||||
const CGHeroInstance *hero;
|
||||
PrimarySkill::PrimarySkill primskill;
|
||||
ui8 level;
|
||||
std::vector<SecondarySkill> skills;
|
||||
@ -1225,7 +1225,7 @@ struct HeroLevelUp : public Query//2000
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & queryID & heroid & primskill & level & skills;
|
||||
h & queryID & hero & primskill & level & skills;
|
||||
}
|
||||
};
|
||||
|
||||
@ -1234,8 +1234,7 @@ struct CommanderLevelUp : public Query
|
||||
void applyCl(CClient *cl);
|
||||
DLL_LINKAGE void applyGs(CGameState *gs);
|
||||
|
||||
ObjectInstanceID heroid; //for commander attached to hero
|
||||
StackLocation sl; //for commander not on the hero?
|
||||
const CGHeroInstance *hero;
|
||||
|
||||
std::vector<ui32> skills; //0-5 - secondary skills, val-100 - special skill
|
||||
|
||||
@ -1243,7 +1242,7 @@ struct CommanderLevelUp : public Query
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & queryID & heroid & sl & skills;
|
||||
h & queryID & hero & skills;
|
||||
}
|
||||
};
|
||||
|
||||
@ -1302,6 +1301,12 @@ struct BlockingDialog : public Query//2003
|
||||
soundID = 0;
|
||||
};
|
||||
|
||||
void addResourceComponents(TResources resources)
|
||||
{
|
||||
for(TResources::nziterator i(resources); i.valid(); i++)
|
||||
components.push_back(Component(Component::RESOURCE, i->resType, i->resVal, 0));
|
||||
}
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & queryID & text & components & player & flags & soundID;
|
||||
|
@ -994,7 +994,7 @@ DLL_LINKAGE void SetHoverName::applyGs( CGameState *gs )
|
||||
|
||||
DLL_LINKAGE void HeroLevelUp::applyGs( CGameState *gs )
|
||||
{
|
||||
CGHeroInstance* h = gs->getHero(heroid);
|
||||
CGHeroInstance* h = gs->getHero(hero->id);
|
||||
h->level = level;
|
||||
//specialty
|
||||
h->Updatespecialty();
|
||||
@ -1002,7 +1002,7 @@ DLL_LINKAGE void HeroLevelUp::applyGs( CGameState *gs )
|
||||
|
||||
DLL_LINKAGE void CommanderLevelUp::applyGs (CGameState *gs)
|
||||
{
|
||||
CCommanderInstance * commander = gs->getHero(heroid)->commander;
|
||||
CCommanderInstance * commander = gs->getHero(hero->id)->commander;
|
||||
assert (commander);
|
||||
commander->levelUp();
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ void Res::ResourceSet::nziterator::advance()
|
||||
{
|
||||
do
|
||||
{
|
||||
cur.resType++;
|
||||
vstd::advance(cur.resType, +1);
|
||||
} while(cur.resType < GameConstants::RESOURCE_QUANTITY && !(cur.resVal=rs[cur.resType]));
|
||||
|
||||
if(cur.resType >= GameConstants::RESOURCE_QUANTITY)
|
||||
@ -102,8 +102,8 @@ void Res::ResourceSet::nziterator::advance()
|
||||
Res::ResourceSet::nziterator::nziterator(const ResourceSet &RS)
|
||||
: rs(RS)
|
||||
{
|
||||
cur.resType = 0;
|
||||
cur.resVal = rs[0];
|
||||
cur.resType = WOOD;
|
||||
cur.resVal = rs[WOOD];
|
||||
|
||||
if(!valid())
|
||||
advance();
|
||||
|
@ -98,6 +98,14 @@ namespace Res
|
||||
return *this;
|
||||
}
|
||||
|
||||
ResourceSet operator-() const
|
||||
{
|
||||
ResourceSet ret;
|
||||
for(int i = 0; i < size(); i++)
|
||||
ret[i] = -at(i);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// WARNING: comparison operators are used for "can afford" relation: a <= b means that foreach i a[i] <= b[i]
|
||||
// that doesn't work the other way: a > b doesn't mean that a cannot be afforded with b, it's still b can afford a
|
||||
// bool operator<(const ResourceSet &rhs)
|
||||
@ -124,7 +132,8 @@ namespace Res
|
||||
{
|
||||
struct ResEntry
|
||||
{
|
||||
TResourceCap resType, resVal;
|
||||
Res::ERes resType;
|
||||
TResourceCap resVal;
|
||||
} cur;
|
||||
const ResourceSet &rs;
|
||||
void advance();
|
||||
|
@ -128,7 +128,7 @@ extern DLL_LINKAGE CLogger * logAi;
|
||||
|
||||
/// RAII class for tracing the program execution.
|
||||
/// It prints "Leaving function XYZ" automatically when the object gets destructed.
|
||||
class DLL_LINKAGE CTraceLogger
|
||||
class DLL_LINKAGE CTraceLogger : boost::noncopyable
|
||||
{
|
||||
public:
|
||||
CTraceLogger(const CLogger * logger, const std::string & beginMessage, const std::string & endMessage);
|
||||
@ -141,10 +141,20 @@ private:
|
||||
|
||||
/// Macros for tracing the control flow of the application conveniently. If the LOG_TRACE macro is used it should be
|
||||
/// the first statement in the function. Logging traces via this macro have almost no impact when the trace is disabled.
|
||||
#define LOG_TRACE(logger) if(logger->isTraceEnabled()) CTraceLogger ctl00(logger, boost::str(boost::format("Entering %s.") % BOOST_CURRENT_FUNCTION), \
|
||||
boost::str(boost::format("Leaving %s.") % BOOST_CURRENT_FUNCTION))
|
||||
#define LOG_TRACE_PARAMS(logger, formatStr, params) if(logger->isTraceEnabled()) CTraceLogger ctl00(logger, boost::str(boost::format("Entering %s: " + \
|
||||
std::string(formatStr) + ".") % BOOST_CURRENT_FUNCTION % params), boost::str(boost::format("Leaving %s.") % BOOST_CURRENT_FUNCTION))
|
||||
///
|
||||
#define RAII_TRACE(logger, onEntry, onLeave) \
|
||||
unique_ptr<CTraceLogger> ctl00; \
|
||||
if(logger->isTraceEnabled()) \
|
||||
ctl00 = make_unique<CTraceLogger>(logger, onEntry, onLeave);
|
||||
|
||||
#define LOG_TRACE(logger) RAII_TRACE(logger, \
|
||||
boost::str(boost::format("Entering %s.") % BOOST_CURRENT_FUNCTION), \
|
||||
boost::str(boost::format("Leaving %s.") % BOOST_CURRENT_FUNCTION))
|
||||
|
||||
|
||||
#define LOG_TRACE_PARAMS(logger, formatStr, params) RAII_TRACE(logger, \
|
||||
boost::str(boost::format("Entering %s: " + std::string(formatStr) + ".") % BOOST_CURRENT_FUNCTION % params), \
|
||||
boost::str(boost::format("Leaving %s.") % BOOST_CURRENT_FUNCTION))
|
||||
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* Implementation/Detail classes, Private API */
|
||||
|
@ -55,7 +55,7 @@ protected:
|
||||
};
|
||||
|
||||
/// The CMapUndoManager provides the functionality to save operations and undo/redo them.
|
||||
class CMapUndoManager
|
||||
class CMapUndoManager : boost::noncopyable
|
||||
{
|
||||
public:
|
||||
CMapUndoManager();
|
||||
@ -87,7 +87,7 @@ private:
|
||||
|
||||
/// The map edit manager provides functionality for drawing terrain and placing
|
||||
/// objects on the map.
|
||||
class DLL_LINKAGE CMapEditManager
|
||||
class DLL_LINKAGE CMapEditManager : boost::noncopyable
|
||||
{
|
||||
public:
|
||||
CMapEditManager(CMap * map);
|
||||
|
@ -56,7 +56,7 @@ class DLL_LINKAGE CMapGenOptions
|
||||
{
|
||||
public:
|
||||
/// The player settings class maps the player color, starting town and human player flag.
|
||||
class CPlayerSettings
|
||||
class DLL_LINKAGE CPlayerSettings
|
||||
{
|
||||
public:
|
||||
CPlayerSettings();
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -7,6 +7,8 @@
|
||||
#include "../lib/IGameCallback.h"
|
||||
#include "../lib/BattleAction.h"
|
||||
#include "../lib/NetPacks.h"
|
||||
#include "CQuery.h"
|
||||
|
||||
|
||||
/*
|
||||
* CGameHandler.h, part of VCMI engine
|
||||
@ -41,13 +43,12 @@ extern boost::mutex gsm;
|
||||
|
||||
struct PlayerStatus
|
||||
{
|
||||
bool makingTurn, engagedIntoBattle;
|
||||
std::set<ui32> queries;
|
||||
bool makingTurn;
|
||||
|
||||
PlayerStatus():makingTurn(false),engagedIntoBattle(false){};
|
||||
PlayerStatus():makingTurn(false){};
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & makingTurn & engagedIntoBattle & queries;
|
||||
h & makingTurn;
|
||||
}
|
||||
};
|
||||
class PlayerStatuses
|
||||
@ -59,11 +60,8 @@ public:
|
||||
|
||||
void addPlayer(PlayerColor player);
|
||||
PlayerStatus operator[](PlayerColor player);
|
||||
int getQueriesCount(PlayerColor player); //returns 0 if there is no such player
|
||||
bool checkFlag(PlayerColor player, bool PlayerStatus::*flag);
|
||||
void setFlag(PlayerColor player, bool PlayerStatus::*flag, bool val);
|
||||
void addQuery(PlayerColor player, ui32 id);
|
||||
void removeQuery(PlayerColor player, ui32 id);
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & players;
|
||||
@ -85,7 +83,6 @@ class CGameHandler : public IGameCallback, CBattleInfoCallback
|
||||
{
|
||||
private:
|
||||
void makeStackDoNothing(const CStack * next);
|
||||
bool isAllowedExchangeForQuery(ObjectInstanceID id1, ObjectInstanceID id2);
|
||||
public:
|
||||
CVCMIServer *s;
|
||||
std::map<PlayerColor, CConnection*> connections; //player color -> connection to client with interface of that player
|
||||
@ -95,25 +92,22 @@ public:
|
||||
//queries stuff
|
||||
boost::recursive_mutex gsm;
|
||||
ui32 QID;
|
||||
Queries queries;
|
||||
|
||||
//TODO get rid of cfunctionlist (or similar) and use serialziable callback structure
|
||||
std::map<ui32, CFunctionList<void(ui32)> > callbacks; //query id => callback function - for selection and yes/no dialogs
|
||||
std::map<ui32, std::pair<ObjectInstanceID, ObjectInstanceID> > allowedExchanges;
|
||||
|
||||
bool isBlockedByQueries(const CPack *pack, int packType, PlayerColor player);
|
||||
bool isValidObject(const CGObjectInstance *obj) const;
|
||||
bool isBlockedByQueries(const CPack *pack, PlayerColor player);
|
||||
bool isAllowedExchange(ObjectInstanceID id1, ObjectInstanceID id2);
|
||||
bool isAllowedArrangePack(const ArrangeStacks *pack);
|
||||
void giveSpells(const CGTownInstance *t, const CGHeroInstance *h);
|
||||
int moveStack(int stack, BattleHex dest); //returned value - travelled distance
|
||||
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(PlayerColor player);
|
||||
void winLoseHandle(ui8 players=255); //players: bit field - colours of players to be checked; default: all
|
||||
void getLossVicMessage(PlayerColor player, si8 standard, bool victory, InfoWindow &out) const;
|
||||
|
||||
////used only in endBattle - don't touch elsewhere
|
||||
boost::function<void(BattleResult*)> * battleEndCallback;
|
||||
//const CArmedInstance * bEndArmy1, * bEndArmy2;
|
||||
bool visitObjectAfterVictory;
|
||||
//
|
||||
void endBattle(int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2); //ends battle
|
||||
@ -137,11 +131,12 @@ public:
|
||||
void changePrimSkill(const CGHeroInstance * hero, PrimarySkill::PrimarySkill which, si64 val, bool abs=false) OVERRIDE;
|
||||
void changeSecSkill(const CGHeroInstance * hero, SecondarySkill which, int val, bool abs=false) OVERRIDE;
|
||||
//void showInfoDialog(InfoWindow *iw) OVERRIDE;
|
||||
void showBlockingDialog(BlockingDialog *iw, const CFunctionList<void(ui32)> &callback) OVERRIDE;
|
||||
ui32 showBlockingDialog(BlockingDialog *iw) OVERRIDE; //synchronous version of above
|
||||
|
||||
void showBlockingDialog(BlockingDialog *iw) OVERRIDE;
|
||||
void showGarrisonDialog(ObjectInstanceID upobj, ObjectInstanceID hid, bool removableUnits, const boost::function<void()> &cb) OVERRIDE;
|
||||
void showThievesGuildWindow(PlayerColor player, ObjectInstanceID requestingObjId) OVERRIDE;
|
||||
void giveResource(PlayerColor player, Res::ERes which, int val) OVERRIDE;
|
||||
void giveResources(PlayerColor player, TResources resources) OVERRIDE;
|
||||
|
||||
void giveCreatures(const CArmedInstance *objid, const CGHeroInstance * h, const CCreatureSet &creatures, bool remove) OVERRIDE;
|
||||
void takeCreatures(ObjectInstanceID objid, const std::vector<CStackBasicDescriptor> &creatures) OVERRIDE;
|
||||
@ -165,11 +160,11 @@ public:
|
||||
void heroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero) OVERRIDE;
|
||||
void stopHeroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero) OVERRIDE;
|
||||
//bool removeArtifact(const CArtifact* art, int hid) OVERRIDE;
|
||||
void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, boost::function<void(BattleResult*)> cb = 0, const CGTownInstance *town = NULL) OVERRIDE; //use hero=NULL for no hero
|
||||
void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, boost::function<void(BattleResult*)> cb = 0, bool creatureBank = false) OVERRIDE; //if any of armies is hero, hero will be used
|
||||
void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, boost::function<void(BattleResult*)> cb = 0, bool creatureBank = false) OVERRIDE; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle//void startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function<void(BattleResult*)> cb) OVERRIDE; //for hero<=>neutral army
|
||||
void startBattlePrimary(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, const CGTownInstance *town = NULL) OVERRIDE; //use hero=NULL for no hero
|
||||
void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, bool creatureBank = false) OVERRIDE; //if any of armies is hero, hero will be used
|
||||
void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, bool creatureBank = false) OVERRIDE; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle//void startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function<void(BattleResult*)> cb) OVERRIDE; //for hero<=>neutral army
|
||||
void setAmount(ObjectInstanceID objid, ui32 val) OVERRIDE;
|
||||
bool moveHero(ObjectInstanceID hid, int3 dst, ui8 instant, PlayerColor asker = PlayerColor::NEUTRAL) OVERRIDE;
|
||||
bool moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, PlayerColor asker = PlayerColor::NEUTRAL) OVERRIDE;
|
||||
void giveHeroBonus(GiveBonus * bonus) OVERRIDE;
|
||||
void setMovePoints(SetMovePoints * smp) OVERRIDE;
|
||||
void setManaPoints(ObjectInstanceID hid, int val) OVERRIDE;
|
||||
@ -179,7 +174,6 @@ public:
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
void useScholarSkill(ObjectInstanceID hero1, ObjectInstanceID hero2);
|
||||
void setPortalDwelling(const CGTownInstance * town, bool forced, bool clear);
|
||||
bool tryAttackingGuard(const int3 &guardPos, const CGHeroInstance * h);
|
||||
void visitObjectOnTile(const TerrainTile &t, const CGHeroInstance * h);
|
||||
bool teleportHero(ObjectInstanceID hid, ObjectInstanceID dstid, ui8 source, PlayerColor asker = PlayerColor::NEUTRAL);
|
||||
void vistiCastleObjects (const CGTownInstance *t, const CGHeroInstance *h);
|
||||
@ -187,7 +181,8 @@ public:
|
||||
void levelUpHero(const CGHeroInstance * hero);//initial call - check if hero have remaining levelups & handle them
|
||||
void levelUpCommander (const CCommanderInstance * c, int skill); //secondary skill 1 to 6, special skill : skill - 100
|
||||
void levelUpCommander (const CCommanderInstance * c);
|
||||
void afterBattleCallback(); // called after level-ups are finished
|
||||
|
||||
void expGiven(const CGHeroInstance *hero); //triggers needed level-ups, handles also commander of this hero
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void commitPackage(CPackForClient *pack) OVERRIDE;
|
||||
@ -233,6 +228,7 @@ public:
|
||||
void handleTownEvents(CGTownInstance *town, NewTurn &n);
|
||||
bool complain(const std::string &problem); //sends message to all clients, prints on the logs and return true
|
||||
void objectVisited( const CGObjectInstance * obj, const CGHeroInstance * h );
|
||||
void objectVisitEnded(const CObjectVisitQuery &query);
|
||||
void engageIntoBattle( PlayerColor player );
|
||||
bool dig(const CGHeroInstance *h);
|
||||
bool castSpell(const CGHeroInstance *h, SpellID spellID, const int3 &pos);
|
||||
@ -240,15 +236,11 @@ public:
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & QID & states;
|
||||
h & QID & states & finishingBattle;
|
||||
}
|
||||
|
||||
ui32 getQueryResult(PlayerColor player, int queryID);
|
||||
void sendMessageToAll(const std::string &message);
|
||||
void sendMessageTo(CConnection &c, const std::string &message);
|
||||
void applyAndAsk(Query * sel, PlayerColor player, boost::function<void(ui32)> &callback);
|
||||
void prepareNewQuery(Query * queryPack, PlayerColor player, const boost::function<void(ui32)> &callback = 0); //generates unique query id and writes it to the pack; blocks the player till query is answered (then callback is called)
|
||||
void ask(Query * sel, PlayerColor player, const CFunctionList<void(ui32)> &callback);
|
||||
void sendToAllClients(CPackForClient * info);
|
||||
void sendAndApply(CPackForClient * info);
|
||||
void applyAndSend(CPackForClient * info);
|
||||
@ -257,6 +249,28 @@ public:
|
||||
void sendAndApply(SetResources * info);
|
||||
void sendAndApply(NewStructures * info);
|
||||
|
||||
struct FinishingBattleHelper
|
||||
{
|
||||
FinishingBattleHelper();
|
||||
FinishingBattleHelper(shared_ptr<const CBattleQuery> Query, bool Duel, int RemainingBattleQueriesCount);
|
||||
|
||||
shared_ptr<const CBattleQuery> query;
|
||||
const CGHeroInstance *winnerHero, *loserHero;
|
||||
PlayerColor victor, loser;
|
||||
bool duel;
|
||||
|
||||
int remainingBattleQueriesCount;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & query & winnerHero & loserHero & victor & loser & duel & remainingBattleQueriesCount;
|
||||
}
|
||||
};
|
||||
|
||||
unique_ptr<FinishingBattleHelper> finishingBattle;
|
||||
|
||||
void battleAfterLevelUp(const BattleResult &result);
|
||||
|
||||
void run(bool resume);
|
||||
void newTurn();
|
||||
void handleAttackBeforeCasting (const BattleAttack & bat);
|
||||
|
@ -6,6 +6,7 @@ include_directories(${Boost_INCLUDE_DIRS})
|
||||
|
||||
set(server_SRCS
|
||||
CGameHandler.cpp
|
||||
CQuery.cpp
|
||||
CVCMIServer.cpp
|
||||
NetPacksServer.cpp
|
||||
)
|
||||
|
342
server/CQuery.cpp
Normal file
342
server/CQuery.cpp
Normal file
@ -0,0 +1,342 @@
|
||||
#include "StdInc.h"
|
||||
#include "CQuery.h"
|
||||
#include "CGameHandler.h"
|
||||
#include "..\lib\BattleState.h"
|
||||
|
||||
boost::mutex Queries::mx;
|
||||
|
||||
template <typename Container>
|
||||
std::string formatContainer(const Container &c, std::string delimeter=", ", std::string opener="(", std::string closer=")")
|
||||
{
|
||||
std::string ret = opener;
|
||||
auto itr = boost::begin(c);
|
||||
if(itr != boost::end(c))
|
||||
{
|
||||
ret += boost::lexical_cast<std::string>(*itr);
|
||||
while(++itr != boost::end(c))
|
||||
{
|
||||
ret += delimeter;
|
||||
ret += boost::lexical_cast<std::string>(*itr);
|
||||
}
|
||||
}
|
||||
ret += closer;
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::ostream & operator<<(std::ostream &out, const CQuery &query)
|
||||
{
|
||||
return out << query.toString();
|
||||
}
|
||||
|
||||
std::ostream & operator<<(std::ostream &out, QueryPtr query)
|
||||
{
|
||||
return out << "[" << query.get() << "] " << query->toString();
|
||||
}
|
||||
|
||||
CQuery::CQuery(void)
|
||||
{
|
||||
boost::unique_lock<boost::mutex> l(Queries::mx);
|
||||
|
||||
static TQueryID QID = 1;
|
||||
|
||||
queryID = QID++;
|
||||
logGlobal->traceStream() << "Created a new query with id " << queryID;
|
||||
}
|
||||
|
||||
|
||||
CQuery::~CQuery(void)
|
||||
{
|
||||
logGlobal->traceStream() << "Destructed the query with id " << queryID;
|
||||
}
|
||||
|
||||
void CQuery::addPlayer(PlayerColor color)
|
||||
{
|
||||
if(color.isValidPlayer())
|
||||
{
|
||||
players.push_back(color);
|
||||
}
|
||||
}
|
||||
|
||||
std::string CQuery::toString() const
|
||||
{
|
||||
std::string ret = boost::str(boost::format("A query of type %s and qid=%d affecting players %s") % typeid(*this).name() % queryID % formatContainer(players));
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CQuery::endsByPlayerAnswer() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void CQuery::onRemoval(CGameHandler *gh, PlayerColor color)
|
||||
{
|
||||
}
|
||||
|
||||
bool CQuery::blocksPack(const CPack *pack) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void CQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const
|
||||
{
|
||||
}
|
||||
|
||||
void CQuery::onExposure(CGameHandler *gh, QueryPtr topQuery)
|
||||
{
|
||||
gh->queries.popQuery(*this);
|
||||
}
|
||||
|
||||
CObjectVisitQuery::CObjectVisitQuery(const CGObjectInstance *Obj, const CGHeroInstance *Hero, int3 Tile)
|
||||
: visitedObject(Obj), visitingHero(Hero), tile(Tile)
|
||||
{
|
||||
addPlayer(Hero->tempOwner);
|
||||
}
|
||||
|
||||
bool CObjectVisitQuery::blocksPack(const CPack *pack) const
|
||||
{
|
||||
//During the visit itself ALL actions are blocked.
|
||||
//(However, the visit may trigger a query above that'll pass some.)
|
||||
return true;
|
||||
}
|
||||
|
||||
void CObjectVisitQuery::onRemoval(CGameHandler *gh, PlayerColor color)
|
||||
{
|
||||
gh->objectVisitEnded(*this);
|
||||
}
|
||||
|
||||
void CObjectVisitQuery::onExposure(CGameHandler *gh, QueryPtr topQuery)
|
||||
{
|
||||
//Object may have been removed and deleted.
|
||||
if(gh->isValidObject(visitedObject))
|
||||
topQuery->notifyObjectAboutRemoval(*this);
|
||||
|
||||
gh->queries.popQuery(*this);
|
||||
}
|
||||
|
||||
void Queries::popQuery(PlayerColor player, QueryPtr query)
|
||||
{
|
||||
LOG_TRACE_PARAMS(logGlobal, "player='%s', query='%s'", player % query);
|
||||
if(topQuery(player) != query)
|
||||
{
|
||||
logGlobal->traceStream() << "Cannot remove, not a top!";
|
||||
return;
|
||||
}
|
||||
|
||||
queries[player] -= query;
|
||||
auto nextQuery = topQuery(player);
|
||||
|
||||
query->onRemoval(gh, player);
|
||||
|
||||
//Exposure on query below happens only if removal didnt trigger any new query
|
||||
if(nextQuery && nextQuery == topQuery(player))
|
||||
{
|
||||
nextQuery->onExposure(gh, query);
|
||||
}
|
||||
}
|
||||
|
||||
void Queries::popQuery(const CQuery &query)
|
||||
{
|
||||
LOG_TRACE_PARAMS(logGlobal, "query='%s'", query);
|
||||
|
||||
assert(query.players.size());
|
||||
BOOST_FOREACH(auto player, query.players)
|
||||
{
|
||||
auto top = topQuery(player);
|
||||
if(top.get() == &query)
|
||||
popQuery(top);
|
||||
else
|
||||
logGlobal->traceStream() << "Cannot remove query " << query;
|
||||
}
|
||||
}
|
||||
|
||||
void Queries::popQuery(QueryPtr query)
|
||||
{
|
||||
BOOST_FOREACH(auto player, query->players)
|
||||
popQuery(player, query);
|
||||
}
|
||||
|
||||
void Queries::addQuery(QueryPtr query)
|
||||
{
|
||||
BOOST_FOREACH(auto player, query->players)
|
||||
addQuery(player, query);
|
||||
}
|
||||
|
||||
void Queries::addQuery(PlayerColor player, QueryPtr query)
|
||||
{
|
||||
LOG_TRACE_PARAMS(logGlobal, "player='%s', query='%s'", player % query);
|
||||
queries[player].push_back(query);
|
||||
}
|
||||
|
||||
QueryPtr Queries::topQuery(PlayerColor player)
|
||||
{
|
||||
return vstd::backOrNull(queries[player]);
|
||||
}
|
||||
|
||||
void Queries::popIfTop(QueryPtr query)
|
||||
{
|
||||
popIfTop(*query);
|
||||
}
|
||||
|
||||
void Queries::popIfTop(const CQuery &query)
|
||||
{
|
||||
BOOST_FOREACH(PlayerColor color, query.players)
|
||||
if(topQuery(color).get() == &query)
|
||||
popQuery(color, topQuery(color));
|
||||
}
|
||||
|
||||
std::vector<shared_ptr<const CQuery>> Queries::allQueries() const
|
||||
{
|
||||
std::vector<shared_ptr<const CQuery>> ret;
|
||||
BOOST_FOREACH(auto &playerQueries, queries)
|
||||
BOOST_FOREACH(auto &query, playerQueries.second)
|
||||
ret.push_back(query);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<shared_ptr<CQuery>> Queries::allQueries()
|
||||
{
|
||||
//TODO code duplication with const function :(
|
||||
std::vector<shared_ptr<CQuery>> ret;
|
||||
BOOST_FOREACH(auto &playerQueries, queries)
|
||||
BOOST_FOREACH(auto &query, playerQueries.second)
|
||||
ret.push_back(query);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CBattleQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const
|
||||
{
|
||||
assert(result);
|
||||
objectVisit.visitedObject->battleFinished(objectVisit.visitingHero, *result);
|
||||
}
|
||||
|
||||
CBattleQuery::CBattleQuery(const BattleInfo *Bi)
|
||||
{
|
||||
belligerents[0] = Bi->belligerents[0];
|
||||
belligerents[1] = Bi->belligerents[1];
|
||||
|
||||
bi = Bi;
|
||||
|
||||
BOOST_FOREACH(PlayerColor side, bi->sides)
|
||||
addPlayer(side);
|
||||
}
|
||||
|
||||
CBattleQuery::CBattleQuery()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool CBattleQuery::blocksPack(const CPack *pack) const
|
||||
{
|
||||
return !dynamic_cast<const MakeAction*>(pack) && !dynamic_cast<const MakeCustomAction*>(pack);
|
||||
}
|
||||
|
||||
void CBattleQuery::onRemoval(CGameHandler *gh, PlayerColor color)
|
||||
{
|
||||
gh->battleAfterLevelUp(*result);
|
||||
}
|
||||
|
||||
void CGarrisonDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const
|
||||
{
|
||||
objectVisit.visitedObject->garrisonDialogClosed(objectVisit.visitingHero);
|
||||
}
|
||||
|
||||
CGarrisonDialogQuery::CGarrisonDialogQuery(const CArmedInstance *up, const CArmedInstance *down)
|
||||
{
|
||||
exchangingArmies[0] = up;
|
||||
exchangingArmies[1] = down;
|
||||
|
||||
addPlayer(up->tempOwner);
|
||||
addPlayer(down->tempOwner);
|
||||
}
|
||||
|
||||
bool CGarrisonDialogQuery::blocksPack(const CPack *pack) const
|
||||
{
|
||||
if(auto stacks = dynamic_cast<const ArrangeStacks*>(pack))
|
||||
{
|
||||
std::set<ObjectInstanceID> ourIds;
|
||||
ourIds.insert(this->exchangingArmies[0]->id);
|
||||
ourIds.insert(this->exchangingArmies[1]->id);
|
||||
|
||||
return !vstd::contains(ourIds, stacks->id1) || !vstd::contains(ourIds, stacks->id2);
|
||||
}
|
||||
|
||||
return CDialogQuery::blocksPack(pack);
|
||||
}
|
||||
|
||||
void CBlockingDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const
|
||||
{
|
||||
assert(answer);
|
||||
objectVisit.visitedObject->blockingDialogAnswered(objectVisit.visitingHero, *answer);
|
||||
}
|
||||
|
||||
CBlockingDialogQuery::CBlockingDialogQuery(const BlockingDialog &bd)
|
||||
{
|
||||
this->bd = bd;
|
||||
addPlayer(bd.player);
|
||||
}
|
||||
|
||||
CHeroLevelUpDialogQuery::CHeroLevelUpDialogQuery(const HeroLevelUp &Hlu)
|
||||
{
|
||||
hlu = Hlu;
|
||||
addPlayer(hlu.hero->tempOwner);
|
||||
}
|
||||
|
||||
void CHeroLevelUpDialogQuery::onRemoval(CGameHandler *gh, PlayerColor color)
|
||||
{
|
||||
assert(answer);
|
||||
logGlobal->traceStream() << "Completing hero level-up query. " << hlu.hero->getHoverText() << " gains skill " << answer;
|
||||
gh->levelUpHero(hlu.hero, hlu.skills[*answer]);
|
||||
}
|
||||
|
||||
CCommanderLevelUpDialogQuery::CCommanderLevelUpDialogQuery(const CommanderLevelUp &Clu)
|
||||
{
|
||||
clu = Clu;
|
||||
addPlayer(clu.hero->tempOwner);
|
||||
}
|
||||
|
||||
void CCommanderLevelUpDialogQuery::onRemoval(CGameHandler *gh, PlayerColor color)
|
||||
{
|
||||
assert(answer);
|
||||
logGlobal->traceStream() << "Completing commander level-up query. Commander of hero " << clu.hero->getHoverText() << " gains skill " << answer;
|
||||
gh->levelUpCommander(clu.hero->commander, clu.skills[*answer]);
|
||||
}
|
||||
|
||||
bool CDialogQuery::endsByPlayerAnswer() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDialogQuery::blocksPack(const CPack *pack) const
|
||||
{
|
||||
//We accept only query replies from correct player
|
||||
if(auto reply = dynamic_cast<const QueryReply *>(pack))
|
||||
{
|
||||
return !vstd::contains(players, reply->player);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CHeroMovementQuery::CHeroMovementQuery(const TryMoveHero &Tmh, const CGHeroInstance *Hero, bool VisitDestAfterVictory)
|
||||
: tmh(Tmh), visitDestAfterVictory(VisitDestAfterVictory), hero(Hero)
|
||||
{
|
||||
players.push_back(hero->tempOwner);
|
||||
}
|
||||
|
||||
void CHeroMovementQuery::onExposure(CGameHandler *gh, QueryPtr topQuery)
|
||||
{
|
||||
assert(players.size() == 1);
|
||||
|
||||
if(visitDestAfterVictory && hero->tempOwner == players[0]) //hero still alive, so he won with the guard
|
||||
//TODO what if there were H4-like escape? we should also check pos
|
||||
{
|
||||
logGlobal->traceStream() << "Hero " << hero->name << " after victory over guard finishes visit to " << tmh.end;
|
||||
//finish movement
|
||||
visitDestAfterVictory = false;
|
||||
gh->visitObjectOnTile(*gh->getTile(CGHeroInstance::convertPosition(tmh.end, false)), hero);
|
||||
}
|
||||
|
||||
gh->queries.popIfTop(*this);
|
||||
}
|
177
server/CQuery.h
Normal file
177
server/CQuery.h
Normal file
@ -0,0 +1,177 @@
|
||||
#pragma once
|
||||
#include "..\lib\GameConstants.h"
|
||||
#include "..\lib\int3.h"
|
||||
#include "..\lib\NetPacks.h"
|
||||
|
||||
class CGObjectInstance;
|
||||
class CGHeroInstance;
|
||||
class CArmedInstance;
|
||||
struct CPack;
|
||||
class CGameHandler;
|
||||
class CObjectVisitQuery;
|
||||
struct TryMoveHero;
|
||||
class CQuery;
|
||||
|
||||
typedef si32 TQueryID;
|
||||
typedef shared_ptr<CQuery> QueryPtr;
|
||||
|
||||
// This class represents any kind of prolonged interaction that may need to do something special after it is over.
|
||||
// It does not necessarily has to be "query" requiring player action, it can be also used internally within server.
|
||||
// Examples:
|
||||
// - all kinds of blocking dialog windows
|
||||
// - battle
|
||||
// - object visit
|
||||
// - hero movement
|
||||
// Queries can cause another queries, forming a stack of queries for each player. Eg: hero movement -> object visit -> dialog.
|
||||
class CQuery
|
||||
{
|
||||
protected:
|
||||
void addPlayer(PlayerColor color);
|
||||
public:
|
||||
std::vector<PlayerColor> players; //players that are affected (often "blocked") by query
|
||||
TQueryID queryID;
|
||||
|
||||
CQuery(void);
|
||||
|
||||
|
||||
virtual bool blocksPack(const CPack *pack) const; //query can block attempting actions by player. Eg. he can't move hero during the battle.
|
||||
|
||||
virtual bool endsByPlayerAnswer() const; //query is removed after player gives answer (like dialogs)
|
||||
virtual void onRemoval(CGameHandler *gh, PlayerColor color); //called after query is removed from stack
|
||||
virtual void onExposure(CGameHandler *gh, QueryPtr topQuery);//called when query immediately above is removed and this is exposed (becomes top)
|
||||
virtual std::string toString() const;
|
||||
|
||||
virtual void notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const;
|
||||
|
||||
virtual ~CQuery(void);
|
||||
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & players & queryID;
|
||||
}
|
||||
};
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const CQuery &query);
|
||||
std::ostream &operator<<(std::ostream &out, QueryPtr query);
|
||||
|
||||
//Created when hero visits object.
|
||||
//Removed when query above is resolved (or immediately after visit if no queries were created)
|
||||
class CObjectVisitQuery : public CQuery
|
||||
{
|
||||
public:
|
||||
const CGObjectInstance *visitedObject;
|
||||
const CGHeroInstance *visitingHero;
|
||||
int3 tile; //may be different than hero pos -> eg. visit via teleport
|
||||
|
||||
CObjectVisitQuery(const CGObjectInstance *Obj, const CGHeroInstance *Hero, int3 Tile);
|
||||
|
||||
virtual bool blocksPack(const CPack *pack) const OVERRIDE;
|
||||
virtual void onRemoval(CGameHandler *gh, PlayerColor color) OVERRIDE;
|
||||
virtual void onExposure(CGameHandler *gh, QueryPtr topQuery) OVERRIDE;
|
||||
};
|
||||
|
||||
class CBattleQuery : public CQuery
|
||||
{
|
||||
public:
|
||||
std::array<const CArmedInstance *,2> belligerents;
|
||||
|
||||
const BattleInfo *bi;
|
||||
boost::optional<BattleResult> result;
|
||||
|
||||
CBattleQuery();
|
||||
CBattleQuery(const BattleInfo *Bi); //TODO
|
||||
virtual void notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const OVERRIDE;
|
||||
virtual bool blocksPack(const CPack *pack) const OVERRIDE;
|
||||
virtual void onRemoval(CGameHandler *gh, PlayerColor color) OVERRIDE;
|
||||
};
|
||||
|
||||
//Created when hero attempts move and something happens
|
||||
//(not necessarily position change, could be just an object interaction).
|
||||
class CHeroMovementQuery : public CQuery
|
||||
{
|
||||
public:
|
||||
TryMoveHero tmh;
|
||||
bool visitDestAfterVictory; //if hero moved to guarded tile and it should be visited once guard is defeated
|
||||
const CGHeroInstance *hero;
|
||||
|
||||
virtual void onExposure(CGameHandler *gh, QueryPtr topQuery);
|
||||
|
||||
CHeroMovementQuery(const TryMoveHero &Tmh, const CGHeroInstance *Hero, bool VisitDestAfterVictory = false);
|
||||
};
|
||||
|
||||
class CDialogQuery : public CQuery
|
||||
{
|
||||
public:
|
||||
boost::optional<ui32> answer;
|
||||
virtual bool endsByPlayerAnswer() const OVERRIDE;
|
||||
virtual bool blocksPack(const CPack *pack) const OVERRIDE;
|
||||
};
|
||||
|
||||
class CGarrisonDialogQuery : public CDialogQuery
|
||||
{
|
||||
public:
|
||||
std::array<const CArmedInstance *,2> exchangingArmies;
|
||||
|
||||
CGarrisonDialogQuery(const CArmedInstance *up, const CArmedInstance *down);
|
||||
virtual void notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const OVERRIDE;
|
||||
virtual bool blocksPack(const CPack *pack) const OVERRIDE;
|
||||
};
|
||||
|
||||
//yes/no and component selection dialogs
|
||||
class CBlockingDialogQuery : public CDialogQuery
|
||||
{
|
||||
public:
|
||||
BlockingDialog bd; //copy of pack... debug purposes
|
||||
|
||||
CBlockingDialogQuery(const BlockingDialog &bd);
|
||||
|
||||
virtual void notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const OVERRIDE;
|
||||
};
|
||||
|
||||
class CHeroLevelUpDialogQuery : public CDialogQuery
|
||||
{
|
||||
public:
|
||||
CHeroLevelUpDialogQuery(const HeroLevelUp &Hlu);
|
||||
|
||||
virtual void onRemoval(CGameHandler *gh, PlayerColor color) OVERRIDE;
|
||||
|
||||
HeroLevelUp hlu;
|
||||
};
|
||||
|
||||
|
||||
class CCommanderLevelUpDialogQuery : public CDialogQuery
|
||||
{
|
||||
public:
|
||||
CCommanderLevelUpDialogQuery(const CommanderLevelUp &Clu);
|
||||
|
||||
virtual void onRemoval(CGameHandler *gh, PlayerColor color) OVERRIDE;
|
||||
|
||||
CommanderLevelUp clu;
|
||||
};
|
||||
|
||||
struct Queries
|
||||
{
|
||||
private:
|
||||
void addQuery(PlayerColor player, QueryPtr query);
|
||||
void popQuery(PlayerColor player, QueryPtr query);
|
||||
|
||||
std::map<PlayerColor, std::vector<QueryPtr>> queries; //player => stack of queries
|
||||
|
||||
public:
|
||||
CGameHandler *gh;
|
||||
static boost::mutex mx;
|
||||
|
||||
void addQuery(QueryPtr query);
|
||||
void popQuery(const CQuery &query);
|
||||
void popQuery(QueryPtr query);
|
||||
void popIfTop(const CQuery &query); //removes this query if it is at the top (otherwise, do nothing)
|
||||
void popIfTop(QueryPtr query); //removes this query if it is at the top (otherwise, do nothing)
|
||||
|
||||
QueryPtr topQuery(PlayerColor player);
|
||||
|
||||
std::vector<shared_ptr<const CQuery>> allQueries() const;
|
||||
std::vector<shared_ptr<CQuery>> allQueries();
|
||||
//void removeQuery
|
||||
|
||||
};
|
@ -69,8 +69,8 @@ bool EndTurn::applyGh( CGameHandler *gh )
|
||||
{
|
||||
PlayerColor player = GS(gh)->currentPlayer;
|
||||
ERROR_IF_NOT(player);
|
||||
if(gh->states.checkFlag(player, &PlayerStatus::engagedIntoBattle))
|
||||
COMPLAIN_AND_RETURN("Cannot end turn when in battle!");
|
||||
if(gh->queries.topQuery(player))
|
||||
COMPLAIN_AND_RETURN("Cannot end turn before resolving queries!");
|
||||
|
||||
gh->states.setFlag(GS(gh)->currentPlayer,&PlayerStatus::makingTurn,false);
|
||||
return true;
|
||||
|
@ -145,6 +145,7 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="CGameHandler.cpp" />
|
||||
<ClCompile Include="CQuery.cpp" />
|
||||
<ClCompile Include="CVCMIServer.cpp" />
|
||||
<ClCompile Include="NetPacksServer.cpp" />
|
||||
<ClCompile Include="StdInc.cpp">
|
||||
@ -158,6 +159,7 @@
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\Global.h" />
|
||||
<ClInclude Include="CGameHandler.h" />
|
||||
<ClInclude Include="CQuery.h" />
|
||||
<ClInclude Include="CVCMIServer.h" />
|
||||
<ClInclude Include="StdInc.h" />
|
||||
</ItemGroup>
|
||||
|
Loading…
Reference in New Issue
Block a user