1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-28 03:57:02 +02:00

Merge pull request #313 from vcmi/spellCastQuery

Spell cast query
This commit is contained in:
ArseniyShestakov 2017-07-04 02:43:22 +03:00 committed by GitHub
commit b670bcb46f
34 changed files with 861 additions and 441 deletions

View File

@ -38,3 +38,8 @@ void CEmptyAI::showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance
{ {
cb->selectionMade(0, queryID); cb->selectionMade(0, queryID);
} }
void CEmptyAI::showMapObjectSelectDialog(QueryID askID, const Component & icon, const MetaString & title, const MetaString & description, const std::vector<ObjectInstanceID> & objects)
{
cb->selectionMade(0, askID);
}

View File

@ -17,6 +17,7 @@ public:
void showBlockingDialog(const std::string &text, const std::vector<Component> &components, QueryID askID, const int soundID, bool selection, bool cancel) override; void showBlockingDialog(const std::string &text, const std::vector<Component> &components, QueryID askID, const int soundID, bool selection, bool cancel) override;
void showTeleportDialog(TeleportChannelID channel, TTeleportExitsList exits, bool impassable, QueryID askID) override; void showTeleportDialog(TeleportChannelID channel, TTeleportExitsList exits, bool impassable, QueryID askID) override;
void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, QueryID queryID) override; void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, QueryID queryID) override;
void showMapObjectSelectDialog(QueryID askID, const Component & icon, const MetaString & title, const MetaString & description, const std::vector<ObjectInstanceID> & objects) override;
}; };
#define NAME "EmptyAI 0.1" #define NAME "EmptyAI 0.1"

View File

@ -701,6 +701,14 @@ void VCAI::showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *do
}); });
} }
void VCAI::showMapObjectSelectDialog(QueryID askID, const Component & icon, const MetaString & title, const MetaString & description, const std::vector<ObjectInstanceID> & objects)
{
status.addQuery(askID, "Map object select query");
requestActionASAP([=]{ answerQuery(askID, 0); });
//TODO: Town portal destination selection goes here
}
void VCAI::saveGame(BinarySerializer & h, const int version) void VCAI::saveGame(BinarySerializer & h, const int version)
{ {
LOG_TRACE_PARAMS(logAi, "version '%i'", version); LOG_TRACE_PARAMS(logAi, "version '%i'", version);

View File

@ -194,6 +194,7 @@ public:
virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &components, QueryID askID, const int soundID, bool selection, bool cancel) override; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID. virtual void showBlockingDialog(const std::string &text, const std::vector<Component> &components, QueryID askID, const int soundID, bool selection, bool cancel) override; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, QueryID queryID) override; //all stacks operations between these objects become allowed, interface has to call onEnd when done virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, QueryID queryID) override; //all stacks operations between these objects become allowed, interface has to call onEnd when done
virtual void showTeleportDialog(TeleportChannelID channel, TTeleportExitsList exits, bool impassable, QueryID askID) override; virtual void showTeleportDialog(TeleportChannelID channel, TTeleportExitsList exits, bool impassable, QueryID askID) override;
void showMapObjectSelectDialog(QueryID askID, const Component & icon, const MetaString & title, const MetaString & description, const std::vector<ObjectInstanceID> & objects) override;
virtual void saveGame(BinarySerializer & h, const int version) override; //saving virtual void saveGame(BinarySerializer & h, const int version) override; //saving
virtual void loadGame(BinaryDeserializer & h, const int version) override; //loading virtual void loadGame(BinaryDeserializer & h, const int version) override; //loading
virtual void finish() override; virtual void finish() override;

View File

@ -45,15 +45,22 @@ bool CCallback::moveHero(const CGHeroInstance *h, int3 dst, bool transit)
} }
int CCallback::selectionMade(int selection, QueryID queryID) int CCallback::selectionMade(int selection, QueryID queryID)
{
JsonNode reply(JsonNode::DATA_INTEGER);
reply.Integer() = selection;
return sendQueryReply(reply, queryID);
}
int CCallback::sendQueryReply(const JsonNode & reply, QueryID queryID)
{ {
ASSERT_IF_CALLED_WITH_PLAYER ASSERT_IF_CALLED_WITH_PLAYER
if(queryID == QueryID(-1)) if(queryID == QueryID(-1))
{ {
logGlobal->errorStream() << "Cannot answer the query -1!"; logGlobal->errorStream() << "Cannot answer the query -1!";
return false; return -1;
} }
QueryReply pack(queryID,selection); QueryReply pack(queryID, reply);
pack.player = *player; pack.player = *player;
return sendRequest(&pack); return sendRequest(&pack);
} }

View File

@ -61,6 +61,7 @@ public:
virtual void trade(const CGObjectInstance *market, EMarketMode::EMarketMode mode, int id1, int id2, int val1, const CGHeroInstance *hero = nullptr)=0; //mode==0: sell val1 units of id1 resource for id2 resiurce virtual void trade(const CGObjectInstance *market, EMarketMode::EMarketMode mode, int id1, int id2, int val1, const CGHeroInstance *hero = nullptr)=0; //mode==0: sell val1 units of id1 resource for id2 resiurce
virtual int selectionMade(int selection, QueryID queryID) =0; virtual int selectionMade(int selection, QueryID queryID) =0;
virtual int sendQueryReply(const JsonNode & reply, QueryID queryID) =0;
virtual int swapCreatures(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2)=0;//swaps creatures between two possibly different garrisons // TODO: AI-unsafe code - fix it! virtual int swapCreatures(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2)=0;//swaps creatures between two possibly different garrisons // TODO: AI-unsafe code - fix it!
virtual int mergeStacks(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2)=0;//joins first stack to the second (creatures must be same type) virtual int mergeStacks(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2)=0;//joins first stack to the second (creatures must be same type)
virtual int mergeOrSwapStacks(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2) =0; //first goes to the second virtual int mergeOrSwapStacks(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2) =0; //first goes to the second
@ -121,6 +122,7 @@ public:
bool moveHero(const CGHeroInstance *h, int3 dst, bool transit = false) override; //dst must be free, neighbouring tile (this function can move hero only by one tile) bool moveHero(const CGHeroInstance *h, int3 dst, bool transit = false) override; //dst must be free, neighbouring tile (this function can move hero only by one tile)
bool teleportHero(const CGHeroInstance *who, const CGTownInstance *where); bool teleportHero(const CGHeroInstance *who, const CGTownInstance *where);
int selectionMade(int selection, QueryID queryID) override; int selectionMade(int selection, QueryID queryID) override;
int sendQueryReply(const JsonNode & reply, QueryID queryID) override;
int swapCreatures(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2) override; int swapCreatures(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2) override;
int mergeOrSwapStacks(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2) override; //first goes to the second int mergeOrSwapStacks(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2) override; //first goes to the second
int mergeStacks(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2) override; //first goes to the second int mergeStacks(const CArmedInstance *s1, const CArmedInstance *s2, SlotID p1, SlotID p2) override; //first goes to the second

View File

@ -15,6 +15,7 @@
#include "gui/SDL_Extensions.h" #include "gui/SDL_Extensions.h"
#include "widgets/CComponent.h" #include "widgets/CComponent.h"
#include "windows/CTradeWindow.h" #include "windows/CTradeWindow.h"
#include "windows/CSpellWindow.h"
#include "../lib/CConfigHandler.h" #include "../lib/CConfigHandler.h"
#include "battle/CCreatureAnimation.h" #include "battle/CCreatureAnimation.h"
#include "Graphics.h" #include "Graphics.h"
@ -1191,6 +1192,43 @@ void CPlayerInterface::showTeleportDialog(TeleportChannelID channel, TTeleportEx
cb->selectionMade(choosenExit, askID); cb->selectionMade(choosenExit, askID);
} }
void CPlayerInterface::showMapObjectSelectDialog(QueryID askID, const Component & icon, const MetaString & title, const MetaString & description, const std::vector<ObjectInstanceID> & objects)
{
EVENT_HANDLER_CALLED_BY_CLIENT;
auto selectCallback = [=](int selection)
{
JsonNode reply(JsonNode::DATA_INTEGER);
reply.Integer() = selection;
cb->sendQueryReply(reply, askID);
};
auto cancelCallback = [=]()
{
JsonNode reply(JsonNode::DATA_NULL);
cb->sendQueryReply(reply, askID);
};
const std::string localTitle = title.toString();
const std::string localDescription = description.toString();
std::vector<int> tempList;
tempList.reserve(objects.size());
for(auto item : objects)
tempList.push_back(item.getNum());
CComponent * localIconC = new CComponent(icon);
CIntObject * localIcon = localIconC->image;
localIconC->removeChild(localIcon, false);
delete localIconC;
CObjectListWindow * wnd = new CObjectListWindow(tempList, localIcon, localTitle, localDescription, selectCallback);
wnd->onExit = cancelCallback;
GH.pushInt(wnd);
}
void CPlayerInterface::tileRevealed(const std::unordered_set<int3, ShashInt3> &pos) void CPlayerInterface::tileRevealed(const std::unordered_set<int3, ShashInt3> &pos)
{ {
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
@ -2213,13 +2251,16 @@ void CPlayerInterface::viewWorldMap()
void CPlayerInterface::advmapSpellCast(const CGHeroInstance * caster, int spellID) void CPlayerInterface::advmapSpellCast(const CGHeroInstance * caster, int spellID)
{ {
EVENT_HANDLER_CALLED_BY_CLIENT; EVENT_HANDLER_CALLED_BY_CLIENT;
if (spellID == SpellID::FLY || spellID == SpellID::WATER_WALK)
{
eraseCurrentPathOf(caster, false);
}
const CSpell * spell = CGI->spellh->objects[spellID];
if (spellID == SpellID::VIEW_EARTH) if(dynamic_cast<CSpellWindow *>(GH.topInt()))
GH.popIntTotally(GH.topInt());
if(spellID == SpellID::FLY || spellID == SpellID::WATER_WALK)
eraseCurrentPathOf(caster, false);
const CSpell * spell = CGI->spellh->objects.at(spellID);
if(spellID == SpellID::VIEW_EARTH)
{ {
//TODO: implement on server side //TODO: implement on server side
int level = caster->getSpellSchoolLevel(spell); int level = caster->getSpellSchoolLevel(spell);
@ -2227,7 +2268,7 @@ void CPlayerInterface::advmapSpellCast(const CGHeroInstance * caster, int spellI
} }
auto castSoundPath = spell->getCastSound(); auto castSoundPath = spell->getCastSound();
if (!castSoundPath.empty()) if(!castSoundPath.empty())
CCS->soundh->playSound(castSoundPath); CCS->soundh->playSound(castSoundPath);
} }

View File

@ -166,6 +166,7 @@ public:
void showBlockingDialog(const std::string &text, const std::vector<Component> &components, QueryID askID, const int soundID, bool selection, bool cancel) override; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID. void showBlockingDialog(const std::string &text, const std::vector<Component> &components, QueryID askID, const int soundID, bool selection, bool cancel) override; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID.
void showTeleportDialog(TeleportChannelID channel, TTeleportExitsList exits, bool impassable, QueryID askID) override; void showTeleportDialog(TeleportChannelID channel, TTeleportExitsList exits, bool impassable, QueryID askID) override;
void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, QueryID queryID) override; void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, QueryID queryID) override;
void showMapObjectSelectDialog(QueryID askID, const Component & icon, const MetaString & title, const MetaString & description, const std::vector<ObjectInstanceID> & objects) override;
void showPuzzleMap() override; void showPuzzleMap() override;
void viewWorldMap() override; void viewWorldMap() override;
void showMarketWindow(const IMarket *market, const CGHeroInstance *visitor) override; void showMarketWindow(const IMarket *market, const CGHeroInstance *visitor) override;

View File

@ -592,6 +592,11 @@ void TeleportDialog::applyCl(CClient *cl)
CALL_ONLY_THAT_INTERFACE(hero->tempOwner,showTeleportDialog,channel,exits,impassable,queryID); CALL_ONLY_THAT_INTERFACE(hero->tempOwner,showTeleportDialog,channel,exits,impassable,queryID);
} }
void MapObjectSelectDialog::applyCl(CClient * cl)
{
CALL_ONLY_THAT_INTERFACE(player, showMapObjectSelectDialog, queryID, icon, title, description, objects);
}
void BattleStart::applyFirstCl(CClient *cl) void BattleStart::applyFirstCl(CClient *cl)
{ {
//Cannot use the usual macro because curB is not set yet //Cannot use the usual macro because curB is not set yet

View File

@ -636,118 +636,18 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
auto guard = vstd::makeScopeGuard([this] auto guard = vstd::makeScopeGuard([this]
{ {
(owner->myInt->battleInt ? owner->myInt->spellbookSettings.spellbookLastTabBattle : owner->myInt->spellbookSettings.spellbookLastTabAdvmap) = owner->selectedTab; owner->myInt->spellbookSettings.spellbookLastTabAdvmap = owner->selectedTab;
(owner->myInt->battleInt ? owner->myInt->spellbookSettings.spellbookLastPageBattle : owner->myInt->spellbookSettings.spellbokLastPageAdvmap) = owner->currentPage; owner->myInt->spellbookSettings.spellbokLastPageAdvmap = owner->currentPage;
delete owner;
}); });
if(mySpell->id == SpellID::TOWN_PORTAL)
{
//special case
//todo: move to mechanics
std::vector <int> availableTowns;
std::vector <const CGTownInstance*> Towns = owner->myInt->cb->getTownsInfo(false);
vstd::erase_if(Towns, [this](const CGTownInstance * t)
{
const auto relations = owner->myInt->cb->getPlayerRelations(t->tempOwner, owner->myInt->playerID);
return relations == PlayerRelations::ENEMIES;
});
if (Towns.empty())
{
owner->myInt->showInfoDialog(CGI->generaltexth->allTexts[124]);
return;
}
const int movementCost = (h->getSpellSchoolLevel(mySpell) >= 3) ? 200 : 300;
if(h->movement < movementCost)
{
owner->myInt->showInfoDialog(CGI->generaltexth->allTexts[125]);
return;
}
if (h->getSpellSchoolLevel(mySpell) < 2) //not advanced or expert - teleport to nearest available city
{
auto nearest = Towns.cbegin(); //nearest town's iterator
si32 dist = owner->myInt->cb->getTown((*nearest)->id)->pos.dist2dSQ(h->pos);
for (auto i = nearest + 1; i != Towns.cend(); ++i)
{
const CGTownInstance * dest = owner->myInt->cb->getTown((*i)->id);
si32 curDist = dest->pos.dist2dSQ(h->pos);
if (curDist < dist)
{
nearest = i;
dist = curDist;
}
}
if ((*nearest)->visitingHero)
owner->myInt->showInfoDialog(CGI->generaltexth->allTexts[123]);
else
{
const CGTownInstance * town = owner->myInt->cb->getTown((*nearest)->id);
owner->myInt->cb->castSpell(h, mySpell->id, town->visitablePos());// - town->getVisitableOffset());
}
}
else
{ //let the player choose
for(auto & Town : Towns)
{
const CGTownInstance *t = Town;
if (t->visitingHero == nullptr) //empty town and this is
{
availableTowns.push_back(t->id.getNum());//add to the list
}
}
auto castTownPortal = [h](int townId)
{
const CGTownInstance * dest = LOCPLINT->cb->getTown(ObjectInstanceID(townId));
LOCPLINT->cb->castSpell(h, SpellID::TOWN_PORTAL, dest->visitablePos());
};
if (availableTowns.empty())
owner->myInt->showInfoDialog(CGI->generaltexth->allTexts[124]);
else
GH.pushInt (new CObjectListWindow(availableTowns,
new CAnimImage("SPELLSCR",mySpell->id),
CGI->generaltexth->jktexts[40], CGI->generaltexth->jktexts[41],
castTownPortal));
}
return;
}
if(mySpell->id == SpellID::SUMMON_BOAT)
{
//special case
//todo: move to mechanics
int3 pos = h->bestLocation();
if(pos.x < 0)
{
owner->myInt->showInfoDialog(CGI->generaltexth->allTexts[334]); //There is no place to put the boat.
return;
}
}
if(mySpell->getTargetType() == CSpell::LOCATION) if(mySpell->getTargetType() == CSpell::LOCATION)
{
adventureInt->enterCastingMode(mySpell); adventureInt->enterCastingMode(mySpell);
}
else if(mySpell->getTargetType() == CSpell::NO_TARGET) else if(mySpell->getTargetType() == CSpell::NO_TARGET)
{
owner->myInt->cb->castSpell(h, mySpell->id); owner->myInt->cb->castSpell(h, mySpell->id);
}
else else
{
logGlobal->error("Invalid spell target type"); logGlobal->error("Invalid spell target type");
} }
} }
}
} }
void CSpellWindow::SpellArea::clickRight(tribool down, bool previousState) void CSpellWindow::SpellArea::clickRight(tribool down, bool previousState)

View File

@ -1767,7 +1767,7 @@ void CObjectListWindow::init(CIntObject * titlePic, std::string _title, std::str
ok = new CButton(Point(15, 402), "IOKAY.DEF", CButton::tooltip(), std::bind(&CObjectListWindow::elementSelected, this), SDLK_RETURN); ok = new CButton(Point(15, 402), "IOKAY.DEF", CButton::tooltip(), std::bind(&CObjectListWindow::elementSelected, this), SDLK_RETURN);
ok->block(true); ok->block(true);
exit = new CButton( Point(228, 402), "ICANCEL.DEF", CButton::tooltip(), std::bind(&CGuiHandler::popIntTotally,&GH, this), SDLK_ESCAPE); exit = new CButton( Point(228, 402), "ICANCEL.DEF", CButton::tooltip(), std::bind(&CObjectListWindow::exitPressed, this), SDLK_ESCAPE);
if (titlePic) if (titlePic)
{ {
@ -1796,6 +1796,14 @@ void CObjectListWindow::elementSelected()
toCall(where);//and send selected object toCall(where);//and send selected object
} }
void CObjectListWindow::exitPressed()
{
std::function<void()> toCall = onExit;//save
GH.popIntTotally(this);//then destroy window
if(toCall)
toCall();
}
void CObjectListWindow::changeSelection(size_t which) void CObjectListWindow::changeSelection(size_t which)
{ {
ok->block(false); ok->block(false);

View File

@ -166,13 +166,18 @@ class CObjectListWindow : public CWindowObject
std::vector< std::pair<int, std::string> > items;//all items present in list std::vector< std::pair<int, std::string> > items;//all items present in list
void init(CIntObject * titlePic, std::string _title, std::string _descr); void init(CIntObject * titlePic, std::string _title, std::string _descr);
void exitPressed();
public: public:
size_t selected;//index of currently selected item size_t selected;//index of currently selected item
std::function<void()> onExit;//optional exit callback
/// Callback will be called when OK button is pressed, returns id of selected item. initState = initially selected item /// Callback will be called when OK button is pressed, returns id of selected item. initState = initially selected item
/// Image can be nullptr /// Image can be nullptr
///item names will be taken from map objects ///item names will be taken from map objects
CObjectListWindow(const std::vector<int> &_items, CIntObject * titlePic, std::string _title, std::string _descr, CObjectListWindow(const std::vector<int> &_items, CIntObject * titlePic, std::string _title, std::string _descr,
std::function<void(int)> Callback); std::function<void(int)> Callback);
CObjectListWindow(const std::vector<std::string> &_items, CIntObject * titlePic, std::string _title, std::string _descr, CObjectListWindow(const std::vector<std::string> &_items, CIntObject * titlePic, std::string _title, std::string _descr,
std::function<void(int)> Callback); std::function<void(int)> Callback);

View File

@ -98,6 +98,7 @@ public:
// all stacks operations between these objects become allowed, interface has to call onEnd when done // all stacks operations between these objects become allowed, interface has to call onEnd when done
virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, QueryID queryID) = 0; virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, QueryID queryID) = 0;
virtual void showTeleportDialog(TeleportChannelID channel, TTeleportExitsList exits, bool impassable, QueryID askID) = 0; virtual void showTeleportDialog(TeleportChannelID channel, TTeleportExitsList exits, bool impassable, QueryID askID) = 0;
virtual void showMapObjectSelectDialog(QueryID askID, const Component & icon, const MetaString & title, const MetaString & description, const std::vector<ObjectInstanceID> & objects) = 0;
virtual void finish(){}; //if for some reason we want to end virtual void finish(){}; //if for some reason we want to end
virtual void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions){}; virtual void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions){};

View File

@ -146,6 +146,9 @@ void MetaString::getLocalString(const std::pair<ui8,ui32> &txt, std::string &dst
case COLOR: case COLOR:
vec = &VLC->generaltexth->capColors; vec = &VLC->generaltexth->capColors;
break; break;
case JK_TXT:
vec = &VLC->generaltexth->jktexts;
break;
default: default:
logGlobal->errorStream() << "Failed string substitution because type is " << type; logGlobal->errorStream() << "Failed string substitution because type is " << type;
dst = "#@#"; dst = "#@#";

View File

@ -3,6 +3,7 @@
#include "NetPacksBase.h" #include "NetPacksBase.h"
#include "battle/BattleAction.h" #include "battle/BattleAction.h"
#include "JsonNode.h"
#include "mapObjects/CGHeroInstance.h" #include "mapObjects/CGHeroInstance.h"
#include "ConstTransitivePtr.h" #include "ConstTransitivePtr.h"
#include "int3.h" #include "int3.h"
@ -1141,12 +1142,6 @@ struct BlockingDialog : public Query
soundID = 0; 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) template <typename Handler> void serialize(Handler &h, const int version)
{ {
h & queryID & text & components & player & flags & soundID; h & queryID & text & components & player & flags & soundID;
@ -1205,6 +1200,24 @@ struct TeleportDialog : public Query
} }
}; };
struct MapObjectSelectDialog : public Query
{
PlayerColor player;
Component icon;
MetaString title;
MetaString description;
std::vector<ObjectInstanceID> objects;
MapObjectSelectDialog(){};
void applyCl(CClient * cl);
template <typename Handler> void serialize(Handler & h, const int version)
{
h & queryID & player & icon & title & description & objects;
}
};
struct BattleInfo; struct BattleInfo;
struct BattleStart : public CPackForClient struct BattleStart : public CPackForClient
{ {
@ -2058,16 +2071,16 @@ struct BuildBoat : public CPackForServer
struct QueryReply : public CPackForServer struct QueryReply : public CPackForServer
{ {
QueryReply():answer(0){}; QueryReply(){};
QueryReply(QueryID QID, ui32 Answer):qid(QID),answer(Answer){}; QueryReply(QueryID QID, const JsonNode & Reply):qid(QID), reply(Reply){};
QueryID qid; QueryID qid;
ui32 answer; //hero and artifact id
PlayerColor player; PlayerColor player;
JsonNode reply;
bool applyGh(CGameHandler *gh); bool applyGh(CGameHandler *gh);
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
h & qid & answer & player; h & qid & player & reply;
} }
}; };

View File

@ -44,11 +44,11 @@ private:
enum EMessage {TEXACT_STRING, TLOCAL_STRING, TNUMBER, TREPLACE_ESTRING, TREPLACE_LSTRING, TREPLACE_NUMBER, TREPLACE_PLUSNUMBER}; enum EMessage {TEXACT_STRING, TLOCAL_STRING, TNUMBER, TREPLACE_ESTRING, TREPLACE_LSTRING, TREPLACE_NUMBER, TREPLACE_PLUSNUMBER};
public: public:
enum {GENERAL_TXT=1, XTRAINFO_TXT, OBJ_NAMES, RES_NAMES, ART_NAMES, ARRAY_TXT, CRE_PL_NAMES, CREGENS, MINE_NAMES, enum {GENERAL_TXT=1, XTRAINFO_TXT, OBJ_NAMES, RES_NAMES, ART_NAMES, ARRAY_TXT, CRE_PL_NAMES, CREGENS, MINE_NAMES,
MINE_EVNTS, ADVOB_TXT, ART_EVNTS, SPELL_NAME, SEC_SKILL_NAME, CRE_SING_NAMES, CREGENS4, COLOR, ART_DESCR}; MINE_EVNTS, ADVOB_TXT, ART_EVNTS, SPELL_NAME, SEC_SKILL_NAME, CRE_SING_NAMES, CREGENS4, COLOR, ART_DESCR, JK_TXT};
std::vector<ui8> message; //vector of EMessage std::vector<ui8> message; //vector of EMessage
std::vector<std::pair<ui8,ui32> > localStrings; //pairs<text handler type, text number>; types: 1 - generaltexthandler->all; 2 - objh->xtrainfo; 3 - objh->names; 4 - objh->restypes; 5 - arth->artifacts[id].name; 6 - generaltexth->arraytxt; 7 - creh->creatures[os->subID].namePl; 8 - objh->creGens; 9 - objh->mines[ID]->first; 10 - objh->mines[ID]->second; 11 - objh->advobtxt std::vector<std::pair<ui8,ui32> > localStrings;
std::vector<std::string> exactStrings; std::vector<std::string> exactStrings;
std::vector<si32> numbers; std::vector<si32> numbers;

View File

@ -290,6 +290,7 @@ void registerTypesClientPacks2(Serializer &s)
s.template registerType<Query, GarrisonDialog>(); s.template registerType<Query, GarrisonDialog>();
s.template registerType<Query, ExchangeDialog>(); s.template registerType<Query, ExchangeDialog>();
s.template registerType<Query, TeleportDialog>(); s.template registerType<Query, TeleportDialog>();
s.template registerType<Query, MapObjectSelectDialog>();
s.template registerType<CPackForClient, CGarrisonOperationPack>(); s.template registerType<CPackForClient, CGarrisonOperationPack>();
s.template registerType<CGarrisonOperationPack, ChangeStackCount>(); s.template registerType<CGarrisonOperationPack, ChangeStackCount>();

View File

@ -20,7 +20,12 @@
#include "../CPlayerState.h" #include "../CPlayerState.h"
///AdventureSpellMechanics ///AdventureSpellMechanics
bool AdventureSpellMechanics::adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const AdventureSpellMechanics::AdventureSpellMechanics(const CSpell * s):
IAdventureSpellMechanics(s)
{
}
bool AdventureSpellMechanics::adventureCast(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
{ {
if(!owner->isAdventureSpell()) if(!owner->isAdventureSpell())
{ {
@ -50,32 +55,15 @@ bool AdventureSpellMechanics::adventureCast(const SpellCastEnvironment * env, Ad
return false; return false;
} }
{ ESpellCastResult result = beginCast(env, parameters);
AdvmapSpellCast asc;
asc.caster = caster;
asc.spellID = owner->id;
env->sendAndApply(&asc);
}
switch(applyAdventureEffects(env, parameters)) if(result == ESpellCastResult::OK)
{ performCast(env, parameters);
case ESpellCastResult::OK:
{ return result != ESpellCastResult::ERROR;
SetMana sm;
sm.hid = caster->id;
sm.absolute = false;
sm.val = -cost;
env->sendAndApply(&sm);
return true;
}
break;
case ESpellCastResult::CANCEL:
return true;
}
return false;
} }
ESpellCastResult AdventureSpellMechanics::applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const ESpellCastResult AdventureSpellMechanics::applyAdventureEffects(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
{ {
if(owner->hasEffects()) if(owner->hasEffects())
{ {
@ -104,10 +92,62 @@ ESpellCastResult AdventureSpellMechanics::applyAdventureEffects(const SpellCastE
} }
} }
///SummonBoatMechanics ESpellCastResult AdventureSpellMechanics::beginCast(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
ESpellCastResult SummonBoatMechanics::applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const
{ {
return ESpellCastResult::OK;
}
void AdventureSpellMechanics::performCast(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
{
AdvmapSpellCast asc;
asc.caster = parameters.caster;
asc.spellID = owner->id;
env->sendAndApply(&asc);
ESpellCastResult result = applyAdventureEffects(env, parameters);
endCast(env, parameters, result);
}
void AdventureSpellMechanics::endCast(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters, const ESpellCastResult result) const
{
const int cost = parameters.caster->getSpellCost(owner);
switch(result)
{
case ESpellCastResult::OK:
{
SetMana sm;
sm.hid = parameters.caster->id;
sm.absolute = false;
sm.val = -cost;
env->sendAndApply(&sm);
}
break;
default:
break;
}
}
///SummonBoatMechanics
SummonBoatMechanics::SummonBoatMechanics(const CSpell * s):
AdventureSpellMechanics(s)
{
}
ESpellCastResult SummonBoatMechanics::applyAdventureEffects(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
{
int3 summonPos = parameters.caster->bestLocation();
if(summonPos.x < 0)
{
InfoWindow iw;
iw.player = parameters.caster->tempOwner;
iw.text.addTxt(MetaString::GENERAL_TXT, 334);//There is no place to put the boat.
env->sendAndApply(&iw);
return ESpellCastResult::CANCEL;
}
const int schoolLevel = parameters.caster->getSpellSchoolLevel(owner); const int schoolLevel = parameters.caster->getSpellSchoolLevel(owner);
//check if spell works at all //check if spell works at all
if(env->getRandomGenerator().nextInt(99) >= owner->getPower(schoolLevel)) //power is % chance of success if(env->getRandomGenerator().nextInt(99) >= owner->getPower(schoolLevel)) //power is % chance of success
{ {
@ -122,13 +162,6 @@ ESpellCastResult SummonBoatMechanics::applyAdventureEffects(const SpellCastEnvir
//try to find unoccupied boat to summon //try to find unoccupied boat to summon
const CGBoat * nearest = nullptr; const CGBoat * nearest = nullptr;
double dist = 0; double dist = 0;
int3 summonPos = parameters.caster->bestLocation();
if(summonPos.x < 0)
{
env->complain("There is no water tile available!");
return ESpellCastResult::ERROR;
}
for(const CGObjectInstance * obj : env->getMap()->objects) for(const CGObjectInstance * obj : env->getMap()->objects)
{ {
if(obj && obj->ID == Obj::BOAT) if(obj && obj->ID == Obj::BOAT)
@ -150,7 +183,7 @@ ESpellCastResult SummonBoatMechanics::applyAdventureEffects(const SpellCastEnvir
{ {
ChangeObjPos cop; ChangeObjPos cop;
cop.objid = nearest->id; cop.objid = nearest->id;
cop.nPos = summonPos + int3(1,0,0);; cop.nPos = summonPos + int3(1,0,0);
cop.flags = 1; cop.flags = 1;
env->sendAndApply(&cop); env->sendAndApply(&cop);
} }
@ -166,14 +199,19 @@ ESpellCastResult SummonBoatMechanics::applyAdventureEffects(const SpellCastEnvir
NewObject no; NewObject no;
no.ID = Obj::BOAT; no.ID = Obj::BOAT;
no.subID = parameters.caster->getBoatType(); no.subID = parameters.caster->getBoatType();
no.pos = summonPos + int3(1,0,0);; no.pos = summonPos + int3(1,0,0);
env->sendAndApply(&no); env->sendAndApply(&no);
} }
return ESpellCastResult::OK; return ESpellCastResult::OK;
} }
///ScuttleBoatMechanics ///ScuttleBoatMechanics
ESpellCastResult ScuttleBoatMechanics::applyAdventureEffects(const SpellCastEnvironment* env, AdventureSpellCastParameters& parameters) const ScuttleBoatMechanics::ScuttleBoatMechanics(const CSpell * s):
AdventureSpellMechanics(s)
{
}
ESpellCastResult ScuttleBoatMechanics::applyAdventureEffects(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
{ {
const int schoolLevel = parameters.caster->getSpellSchoolLevel(owner); const int schoolLevel = parameters.caster->getSpellSchoolLevel(owner);
//check if spell works at all //check if spell works at all
@ -208,7 +246,12 @@ ESpellCastResult ScuttleBoatMechanics::applyAdventureEffects(const SpellCastEnvi
} }
///DimensionDoorMechanics ///DimensionDoorMechanics
ESpellCastResult DimensionDoorMechanics::applyAdventureEffects(const SpellCastEnvironment* env, AdventureSpellCastParameters& parameters) const DimensionDoorMechanics::DimensionDoorMechanics(const CSpell * s):
AdventureSpellMechanics(s)
{
}
ESpellCastResult DimensionDoorMechanics::applyAdventureEffects(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
{ {
if(!env->getMap()->isInTheMap(parameters.pos)) if(!env->getMap()->isInTheMap(parameters.pos))
{ {
@ -276,24 +319,54 @@ ESpellCastResult DimensionDoorMechanics::applyAdventureEffects(const SpellCastEn
} }
///TownPortalMechanics ///TownPortalMechanics
ESpellCastResult TownPortalMechanics::applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters& parameters) const TownPortalMechanics::TownPortalMechanics(const CSpell * s):
AdventureSpellMechanics(s)
{ {
if (!env->getMap()->isInTheMap(parameters.pos)) }
ESpellCastResult TownPortalMechanics::applyAdventureEffects(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
{
const CGTownInstance * destination = nullptr;
const int moveCost = movementCost(parameters);
if(parameters.caster->getSpellSchoolLevel(owner) < 2)
{ {
env->complain("Destination tile not present!"); std::vector <const CGTownInstance*> pool = getPossibleTowns(env, parameters);
destination = findNearestTown(env, parameters, pool);
if(nullptr == destination)
return ESpellCastResult::ERROR;
if(parameters.caster->movement < moveCost)
return ESpellCastResult::ERROR;
if(destination->visitingHero)
{
InfoWindow iw;
iw.player = parameters.caster->tempOwner;
iw.text.addTxt(MetaString::GENERAL_TXT, 123);
env->sendAndApply(&iw);
return ESpellCastResult::CANCEL;
}
}
else if(env->getMap()->isInTheMap(parameters.pos))
{
const TerrainTile & tile = env->getMap()->getTile(parameters.pos);
if(tile.visitableObjects.empty() || tile.visitableObjects.back()->ID != Obj::TOWN)
{
env->complain("No town at destination tile");
return ESpellCastResult::ERROR; return ESpellCastResult::ERROR;
} }
TerrainTile tile = env->getMap()->getTile(parameters.pos); destination = dynamic_cast<CGTownInstance*>(tile.visitableObjects.back());
if (tile.visitableObjects.empty() || tile.visitableObjects.back()->ID != Obj::TOWN)
if(nullptr == destination)
{ {
env->complain("Town not found for Town Portal!"); env->complain("[Internal error] invalid town object");
return ESpellCastResult::ERROR; return ESpellCastResult::ERROR;
} }
CGTownInstance * town = static_cast<CGTownInstance*>(tile.visitableObjects.back()); const auto relations = env->getCb()->getPlayerRelations(destination->tempOwner, parameters.caster->tempOwner);
const auto relations = env->getCb()->getPlayerRelations(town->tempOwner, parameters.caster->tempOwner);
if(relations == PlayerRelations::ENEMIES) if(relations == PlayerRelations::ENEMIES)
{ {
@ -301,52 +374,166 @@ ESpellCastResult TownPortalMechanics::applyAdventureEffects(const SpellCastEnvir
return ESpellCastResult::ERROR; return ESpellCastResult::ERROR;
} }
if (town->visitingHero) if(parameters.caster->movement < moveCost)
{
env->complain("Can't teleport to occupied town!");
return ESpellCastResult::ERROR;
}
if (parameters.caster->getSpellSchoolLevel(owner) < 2)
{
si32 dist = town->pos.dist2dSQ(parameters.caster->pos);
ObjectInstanceID nearest = town->id; //nearest town's ID
for(const CGTownInstance * currTown : env->getCb()->getPlayer(parameters.caster->tempOwner)->towns)
{
si32 currDist = currTown->pos.dist2dSQ(parameters.caster->pos);
if (currDist < dist)
{
nearest = currTown->id;
dist = currDist;
}
}
if (town->id != nearest)
{
env->complain("This hero can only teleport to nearest town!");
return ESpellCastResult::ERROR;
}
}
const int movementCost = GameConstants::BASE_MOVEMENT_COST * ((parameters.caster->getSpellSchoolLevel(owner) >= 3) ? 2 : 3);
if(parameters.caster->movement < movementCost)
{ {
env->complain("This hero has not enough movement points!"); env->complain("This hero has not enough movement points!");
return ESpellCastResult::ERROR; return ESpellCastResult::ERROR;
} }
if(env->moveHero(parameters.caster->id, town->visitablePos() + parameters.caster->getVisitableOffset() ,1)) if(destination->visitingHero)
{
env->complain("Can't teleport to occupied town!");
return ESpellCastResult::ERROR;
}
}
else
{
env->complain("Invalid destination tile");
return ESpellCastResult::ERROR;
}
if(env->moveHero(parameters.caster->id, destination->visitablePos() + parameters.caster->getVisitableOffset(), true))
{ {
SetMovePoints smp; SetMovePoints smp;
smp.hid = parameters.caster->id; smp.hid = parameters.caster->id;
smp.val = std::max<ui32>(0, parameters.caster->movement - movementCost); smp.val = std::max<ui32>(0, parameters.caster->movement - moveCost);
env->sendAndApply(&smp); env->sendAndApply(&smp);
} }
return ESpellCastResult::OK; return ESpellCastResult::OK;
} }
ESpellCastResult ViewMechanics::applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const ESpellCastResult TownPortalMechanics::beginCast(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
{
std::vector<const CGTownInstance *> towns = getPossibleTowns(env, parameters);
if(towns.empty())
{
InfoWindow iw;
iw.player = parameters.caster->tempOwner;
iw.text.addTxt(MetaString::GENERAL_TXT, 124);
env->sendAndApply(&iw);
return ESpellCastResult::CANCEL;
}
const int moveCost = movementCost(parameters);
if(parameters.caster->movement < moveCost)
{
InfoWindow iw;
iw.player = parameters.caster->tempOwner;
iw.text.addTxt(MetaString::GENERAL_TXT, 125);
env->sendAndApply(&iw);
return ESpellCastResult::CANCEL;
}
if(!parameters.pos.valid() && parameters.caster->getSpellSchoolLevel(owner) >= 2)
{
auto queryCallback = [=](const JsonNode & reply) -> void
{
if(reply.getType() == JsonNode::DATA_INTEGER)
{
ObjectInstanceID townId(reply.Integer());
const CGObjectInstance * o = env->getCb()->getObj(townId, true);
if(o == nullptr)
{
env->complain("Invalid object instance selected");
return;
}
if(!dynamic_cast<const CGTownInstance *>(o))
{
env->complain("Object instance is not town");
return;
}
AdventureSpellCastParameters p;
p.caster = parameters.caster;
p.pos = o->visitablePos();
performCast(env, p);
}
};
MapObjectSelectDialog request;
for(auto t : towns)
{
if(t->visitingHero == nullptr) //empty town
request.objects.push_back(t->id);
}
if(request.objects.empty())
{
InfoWindow iw;
iw.player = parameters.caster->tempOwner;
iw.text.addTxt(MetaString::GENERAL_TXT, 124);
env->sendAndApply(&iw);
return ESpellCastResult::CANCEL;
}
request.player = parameters.caster->getOwner();
request.title.addTxt(MetaString::JK_TXT, 40);
request.description.addTxt(MetaString::JK_TXT, 41);
request.icon.id = Component::SPELL;
request.icon.subtype = owner->id.toEnum();
env->genericQuery(&request, request.player, queryCallback);
return ESpellCastResult::PENDING;
}
return ESpellCastResult::OK;
}
const CGTownInstance * TownPortalMechanics::findNearestTown(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters, const std::vector <const CGTownInstance *> & pool) const
{
if(pool.empty())
return nullptr;
auto nearest = pool.cbegin(); //nearest town's iterator
si32 dist = (*nearest)->pos.dist2dSQ(parameters.caster->pos);
for(auto i = nearest + 1; i != pool.cend(); ++i)
{
si32 curDist = (*i)->pos.dist2dSQ(parameters.caster->pos);
if(curDist < dist)
{
nearest = i;
dist = curDist;
}
}
return *nearest;
}
std::vector <const CGTownInstance*> TownPortalMechanics::getPossibleTowns(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
{
std::vector <const CGTownInstance*> ret;
const TeamState * team = env->getCb()->getPlayerTeam(parameters.caster->getOwner());
for(const auto & color : team->players)
{
for(auto currTown : env->getCb()->getPlayer(color)->towns)
{
ret.push_back(currTown.get());
}
}
return ret;
}
int TownPortalMechanics::movementCost(const AdventureSpellCastParameters & parameters) const
{
return GameConstants::BASE_MOVEMENT_COST * ((parameters.caster->getSpellSchoolLevel(owner) >= 3) ? 2 : 3);
}
///ViewMechanics
ViewMechanics::ViewMechanics(const CSpell * s):
AdventureSpellMechanics(s)
{
}
ESpellCastResult ViewMechanics::applyAdventureEffects(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
{ {
ShowWorldViewEx pack; ShowWorldViewEx pack;
@ -373,13 +560,25 @@ ESpellCastResult ViewMechanics::applyAdventureEffects(const SpellCastEnvironment
return ESpellCastResult::OK; return ESpellCastResult::OK;
} }
///ViewAirMechanics
ViewAirMechanics::ViewAirMechanics(const CSpell * s):
ViewMechanics(s)
{
}
bool ViewAirMechanics::filterObject(const CGObjectInstance * obj, const int spellLevel) const bool ViewAirMechanics::filterObject(const CGObjectInstance * obj, const int spellLevel) const
{ {
return (obj->ID == Obj::ARTIFACT) || (spellLevel>1 && obj->ID == Obj::HERO) || (spellLevel>2 && obj->ID == Obj::TOWN); return (obj->ID == Obj::ARTIFACT) || (spellLevel > 1 && obj->ID == Obj::HERO) || (spellLevel > 2 && obj->ID == Obj::TOWN);
}
///ViewEarthMechanics
ViewEarthMechanics::ViewEarthMechanics(const CSpell * s):
ViewMechanics(s)
{
} }
bool ViewEarthMechanics::filterObject(const CGObjectInstance * obj, const int spellLevel) const bool ViewEarthMechanics::filterObject(const CGObjectInstance * obj, const int spellLevel) const
{ {
return (obj->ID == Obj::RESOURCE) || (spellLevel>1 && obj->ID == Obj::MINE); return (obj->ID == Obj::RESOURCE) || (spellLevel > 1 && obj->ID == Obj::MINE);
} }

View File

@ -12,69 +12,80 @@
#include "ISpellMechanics.h" #include "ISpellMechanics.h"
class CGTownInstance;
enum class ESpellCastResult enum class ESpellCastResult
{ {
OK, OK,
CANCEL,//cast failed but it is not an error CANCEL,//cast failed but it is not an error
PENDING,
ERROR//internal error occurred ERROR//internal error occurred
}; };
class DLL_LINKAGE AdventureSpellMechanics: public IAdventureSpellMechanics class DLL_LINKAGE AdventureSpellMechanics : public IAdventureSpellMechanics
{ {
public: public:
AdventureSpellMechanics(CSpell * s): IAdventureSpellMechanics(s){}; AdventureSpellMechanics(const CSpell * s);
bool adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override final; bool adventureCast(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const override final;
protected: protected:
///actual adventure cast implementation ///actual adventure cast implementation
virtual ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const; virtual ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const;
virtual ESpellCastResult beginCast(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const;
void performCast(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const;
void endCast(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters, const ESpellCastResult result) const;
}; };
class DLL_LINKAGE SummonBoatMechanics : public AdventureSpellMechanics class DLL_LINKAGE SummonBoatMechanics : public AdventureSpellMechanics
{ {
public: public:
SummonBoatMechanics(CSpell * s): AdventureSpellMechanics(s){}; SummonBoatMechanics(const CSpell * s);
protected: protected:
ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override; ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const override;
}; };
class DLL_LINKAGE ScuttleBoatMechanics : public AdventureSpellMechanics class DLL_LINKAGE ScuttleBoatMechanics : public AdventureSpellMechanics
{ {
public: public:
ScuttleBoatMechanics(CSpell * s): AdventureSpellMechanics(s){}; ScuttleBoatMechanics(const CSpell * s);
protected: protected:
ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override; ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const override;
}; };
class DLL_LINKAGE DimensionDoorMechanics : public AdventureSpellMechanics class DLL_LINKAGE DimensionDoorMechanics : public AdventureSpellMechanics
{ {
public: public:
DimensionDoorMechanics(CSpell * s): AdventureSpellMechanics(s){}; DimensionDoorMechanics(const CSpell * s);
protected: protected:
ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override; ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const override;
}; };
class DLL_LINKAGE TownPortalMechanics : public AdventureSpellMechanics class DLL_LINKAGE TownPortalMechanics : public AdventureSpellMechanics
{ {
public: public:
TownPortalMechanics(CSpell * s): AdventureSpellMechanics(s){}; TownPortalMechanics(const CSpell * s);
protected: protected:
ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override; ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const override;
ESpellCastResult beginCast(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const override;
private:
const CGTownInstance * findNearestTown(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters, const std::vector <const CGTownInstance*> & pool) const;
int movementCost(const AdventureSpellCastParameters & parameters) const;
std::vector <const CGTownInstance*> getPossibleTowns(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const;
}; };
class DLL_LINKAGE ViewMechanics : public AdventureSpellMechanics class DLL_LINKAGE ViewMechanics : public AdventureSpellMechanics
{ {
public: public:
ViewMechanics(CSpell * s): AdventureSpellMechanics(s){}; ViewMechanics(const CSpell * s);
protected: protected:
ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const override; ESpellCastResult applyAdventureEffects(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const override;
virtual bool filterObject(const CGObjectInstance * obj, const int spellLevel) const = 0; virtual bool filterObject(const CGObjectInstance * obj, const int spellLevel) const = 0;
}; };
class DLL_LINKAGE ViewAirMechanics : public ViewMechanics class DLL_LINKAGE ViewAirMechanics : public ViewMechanics
{ {
public: public:
ViewAirMechanics(CSpell * s): ViewMechanics(s){}; ViewAirMechanics(const CSpell * s);
protected: protected:
bool filterObject(const CGObjectInstance * obj, const int spellLevel) const override; bool filterObject(const CGObjectInstance * obj, const int spellLevel) const override;
}; };
@ -82,7 +93,7 @@ protected:
class DLL_LINKAGE ViewEarthMechanics : public ViewMechanics class DLL_LINKAGE ViewEarthMechanics : public ViewMechanics
{ {
public: public:
ViewEarthMechanics(CSpell * s): ViewMechanics(s){}; ViewEarthMechanics(const CSpell * s);
protected: protected:
bool filterObject(const CGObjectInstance * obj, const int spellLevel) const override; bool filterObject(const CGObjectInstance * obj, const int spellLevel) const override;
}; };

View File

@ -18,6 +18,11 @@
#include "../mapObjects/CGTownInstance.h" #include "../mapObjects/CGTownInstance.h"
///HealingSpellMechanics ///HealingSpellMechanics
HealingSpellMechanics::HealingSpellMechanics(const CSpell * s):
DefaultSpellMechanics(s)
{
}
void HealingSpellMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const void HealingSpellMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
{ {
EHealLevel healLevel = getHealLevel(parameters.effectLevel); EHealLevel healLevel = getHealLevel(parameters.effectLevel);
@ -48,6 +53,11 @@ int HealingSpellMechanics::calculateHealedHP(const SpellCastEnvironment* env, co
} }
///AntimagicMechanics ///AntimagicMechanics
AntimagicMechanics::AntimagicMechanics(const CSpell * s):
DefaultSpellMechanics(s)
{
}
void AntimagicMechanics::applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const void AntimagicMechanics::applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const
{ {
DefaultSpellMechanics::applyBattle(battle, packet); DefaultSpellMechanics::applyBattle(battle, packet);
@ -74,6 +84,11 @@ void AntimagicMechanics::applyBattle(BattleInfo * battle, const BattleSpellCast
} }
///ChainLightningMechanics ///ChainLightningMechanics
ChainLightningMechanics::ChainLightningMechanics(const CSpell * s):
DefaultSpellMechanics(s)
{
}
std::vector<const CStack *> ChainLightningMechanics::calculateAffectedStacks(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const std::vector<const CStack *> ChainLightningMechanics::calculateAffectedStacks(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const
{ {
std::vector<const CStack *> res; std::vector<const CStack *> res;
@ -111,6 +126,11 @@ std::vector<const CStack *> ChainLightningMechanics::calculateAffectedStacks(con
} }
///CloneMechanics ///CloneMechanics
CloneMechanics::CloneMechanics(const CSpell * s):
DefaultSpellMechanics(s)
{
}
void CloneMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const void CloneMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
{ {
const CStack * clonedStack = nullptr; const CStack * clonedStack = nullptr;
@ -180,10 +200,14 @@ ESpellCastProblem::ESpellCastProblem CloneMechanics::isImmuneByStack(const ISpel
} }
///CureMechanics ///CureMechanics
CureMechanics::CureMechanics(const CSpell * s):
HealingSpellMechanics(s)
{
}
void CureMechanics::applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const void CureMechanics::applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const
{ {
DefaultSpellMechanics::applyBattle(battle, packet); DefaultSpellMechanics::applyBattle(battle, packet);
doDispell(battle, packet, dispellSelector); doDispell(battle, packet, dispellSelector);
} }
@ -212,6 +236,11 @@ ESpellCastProblem::ESpellCastProblem CureMechanics::isImmuneByStack(const ISpell
} }
///DispellMechanics ///DispellMechanics
DispellMechanics::DispellMechanics(const CSpell * s):
DefaultSpellMechanics(s)
{
}
void DispellMechanics::applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const void DispellMechanics::applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const
{ {
DefaultSpellMechanics::applyBattle(battle, packet); DefaultSpellMechanics::applyBattle(battle, packet);
@ -261,6 +290,11 @@ void DispellMechanics::applyBattleEffects(const SpellCastEnvironment * env, cons
} }
///EarthquakeMechanics ///EarthquakeMechanics
EarthquakeMechanics::EarthquakeMechanics(const CSpell * s):
SpecialSpellMechanics(s)
{
}
void EarthquakeMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const void EarthquakeMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
{ {
if(nullptr == parameters.cb->battleGetDefendedTown()) if(nullptr == parameters.cb->battleGetDefendedTown())
@ -391,6 +425,11 @@ bool EarthquakeMechanics::requiresCreatureTarget() const
} }
///HypnotizeMechanics ///HypnotizeMechanics
HypnotizeMechanics::HypnotizeMechanics(const CSpell * s):
DefaultSpellMechanics(s)
{
}
ESpellCastProblem::ESpellCastProblem HypnotizeMechanics::isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const ESpellCastProblem::ESpellCastProblem HypnotizeMechanics::isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const
{ {
//todo: maybe do not resist on passive cast //todo: maybe do not resist on passive cast
@ -407,6 +446,11 @@ ESpellCastProblem::ESpellCastProblem HypnotizeMechanics::isImmuneByStack(const I
} }
///ObstacleMechanics ///ObstacleMechanics
ObstacleMechanics::ObstacleMechanics(const CSpell * s):
SpecialSpellMechanics(s)
{
}
ESpellCastProblem::ESpellCastProblem ObstacleMechanics::canBeCast(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const ESpellCastProblem::ESpellCastProblem ObstacleMechanics::canBeCast(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const
{ {
const auto side = cb->playerToSide(ctx.caster->getOwner()); const auto side = cb->playerToSide(ctx.caster->getOwner());
@ -481,6 +525,11 @@ void ObstacleMechanics::placeObstacle(const SpellCastEnvironment * env, const Ba
} }
///PatchObstacleMechanics ///PatchObstacleMechanics
PatchObstacleMechanics::PatchObstacleMechanics(const CSpell * s):
ObstacleMechanics(s)
{
}
void PatchObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const void PatchObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
{ {
std::vector<BattleHex> availableTiles; std::vector<BattleHex> availableTiles;
@ -500,6 +549,11 @@ void PatchObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env
} }
///LandMineMechanics ///LandMineMechanics
LandMineMechanics::LandMineMechanics(const CSpell * s):
PatchObstacleMechanics(s)
{
}
ESpellCastProblem::ESpellCastProblem LandMineMechanics::canBeCast(const CBattleInfoCallback * cb, const ECastingMode::ECastingMode mode, const ISpellCaster * caster) const ESpellCastProblem::ESpellCastProblem LandMineMechanics::canBeCast(const CBattleInfoCallback * cb, const ECastingMode::ECastingMode mode, const ISpellCaster * caster) const
{ {
//LandMine are useless if enemy has native stack and can see mines, check for LandMine damage immunity is done in general way by CSpell //LandMine are useless if enemy has native stack and can see mines, check for LandMine damage immunity is done in general way by CSpell
@ -528,6 +582,11 @@ void LandMineMechanics::setupObstacle(SpellCreatedObstacle * obstacle) const
} }
///QuicksandMechanics ///QuicksandMechanics
QuicksandMechanics::QuicksandMechanics(const CSpell * s):
PatchObstacleMechanics(s)
{
}
bool QuicksandMechanics::requiresCreatureTarget() const bool QuicksandMechanics::requiresCreatureTarget() const
{ {
return false; return false;
@ -541,6 +600,11 @@ void QuicksandMechanics::setupObstacle(SpellCreatedObstacle * obstacle) const
} }
///WallMechanics ///WallMechanics
WallMechanics::WallMechanics(const CSpell * s):
ObstacleMechanics(s)
{
}
std::vector<BattleHex> WallMechanics::rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool * outDroppedHexes) const std::vector<BattleHex> WallMechanics::rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool * outDroppedHexes) const
{ {
std::vector<BattleHex> ret; std::vector<BattleHex> ret;
@ -578,6 +642,11 @@ std::vector<BattleHex> WallMechanics::rangeInHexes(BattleHex centralHex, ui8 sch
} }
///FireWallMechanics ///FireWallMechanics
FireWallMechanics::FireWallMechanics(const CSpell * s):
WallMechanics(s)
{
}
bool FireWallMechanics::requiresCreatureTarget() const bool FireWallMechanics::requiresCreatureTarget() const
{ {
return true; return true;
@ -606,6 +675,11 @@ void FireWallMechanics::setupObstacle(SpellCreatedObstacle * obstacle) const
} }
///ForceFieldMechanics ///ForceFieldMechanics
ForceFieldMechanics::ForceFieldMechanics(const CSpell * s):
WallMechanics(s)
{
}
bool ForceFieldMechanics::requiresCreatureTarget() const bool ForceFieldMechanics::requiresCreatureTarget() const
{ {
return false; return false;
@ -631,6 +705,11 @@ void ForceFieldMechanics::setupObstacle(SpellCreatedObstacle * obstacle) const
} }
///RemoveObstacleMechanics ///RemoveObstacleMechanics
RemoveObstacleMechanics::RemoveObstacleMechanics(const CSpell * s):
SpecialSpellMechanics(s)
{
}
void RemoveObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const void RemoveObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
{ {
auto obstacleToRemove = parameters.cb->battleGetAllObstaclesOnPos(parameters.getFirstDestinationHex(), false); auto obstacleToRemove = parameters.cb->battleGetAllObstaclesOnPos(parameters.getFirstDestinationHex(), false);
@ -714,6 +793,11 @@ bool RemoveObstacleMechanics::requiresCreatureTarget() const
} }
///RisingSpellMechanics ///RisingSpellMechanics
RisingSpellMechanics::RisingSpellMechanics(const CSpell * s):
HealingSpellMechanics(s)
{
}
HealingSpellMechanics::EHealLevel RisingSpellMechanics::getHealLevel(int effectLevel) const HealingSpellMechanics::EHealLevel RisingSpellMechanics::getHealLevel(int effectLevel) const
{ {
//this may be even distinct class //this may be even distinct class
@ -724,6 +808,11 @@ HealingSpellMechanics::EHealLevel RisingSpellMechanics::getHealLevel(int effectL
} }
///SacrificeMechanics ///SacrificeMechanics
SacrificeMechanics::SacrificeMechanics(const CSpell * s):
RisingSpellMechanics(s)
{
}
ESpellCastProblem::ESpellCastProblem SacrificeMechanics::canBeCast(const CBattleInfoCallback * cb, const ECastingMode::ECastingMode mode, const ISpellCaster * caster) const ESpellCastProblem::ESpellCastProblem SacrificeMechanics::canBeCast(const CBattleInfoCallback * cb, const ECastingMode::ECastingMode mode, const ISpellCaster * caster) const
{ {
if(mode == ECastingMode::AFTER_ATTACK_CASTING || mode == ECastingMode::SPELL_LIKE_ATTACK || mode == ECastingMode::MAGIC_MIRROR) if(mode == ECastingMode::AFTER_ATTACK_CASTING || mode == ECastingMode::SPELL_LIKE_ATTACK || mode == ECastingMode::MAGIC_MIRROR)
@ -809,6 +898,11 @@ bool SacrificeMechanics::requiresCreatureTarget() const
} }
///SpecialRisingSpellMechanics ///SpecialRisingSpellMechanics
SpecialRisingSpellMechanics::SpecialRisingSpellMechanics(const CSpell * s):
RisingSpellMechanics(s)
{
}
ESpellCastProblem::ESpellCastProblem SpecialRisingSpellMechanics::canBeCast(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const ESpellCastProblem::ESpellCastProblem SpecialRisingSpellMechanics::canBeCast(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const
{ {
//find alive possible target //find alive possible target
@ -870,6 +964,11 @@ ESpellCastProblem::ESpellCastProblem SpecialRisingSpellMechanics::isImmuneByStac
} }
///SummonMechanics ///SummonMechanics
SummonMechanics::SummonMechanics(const CSpell * s, CreatureID cre):
SpecialSpellMechanics(s), creatureToSummon(cre)
{
}
ESpellCastProblem::ESpellCastProblem SummonMechanics::canBeCast(const CBattleInfoCallback * cb, const ECastingMode::ECastingMode mode, const ISpellCaster * caster) const ESpellCastProblem::ESpellCastProblem SummonMechanics::canBeCast(const CBattleInfoCallback * cb, const ECastingMode::ECastingMode mode, const ISpellCaster * caster) const
{ {
if(mode == ECastingMode::AFTER_ATTACK_CASTING || mode == ECastingMode::SPELL_LIKE_ATTACK || mode == ECastingMode::MAGIC_MIRROR) if(mode == ECastingMode::AFTER_ATTACK_CASTING || mode == ECastingMode::SPELL_LIKE_ATTACK || mode == ECastingMode::MAGIC_MIRROR)
@ -920,6 +1019,11 @@ bool SummonMechanics::requiresCreatureTarget() const
} }
///TeleportMechanics ///TeleportMechanics
TeleportMechanics::TeleportMechanics(const CSpell * s):
DefaultSpellMechanics(s)
{
}
void TeleportMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const void TeleportMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
{ {
if(parameters.destinations.size() == 2) if(parameters.destinations.size() == 2)

View File

@ -25,7 +25,7 @@ public:
TRUE_RESURRECT TRUE_RESURRECT
}; };
HealingSpellMechanics(CSpell * s): DefaultSpellMechanics(s){}; HealingSpellMechanics(const CSpell * s);
protected: protected:
void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override; void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
virtual int calculateHealedHP(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const; virtual int calculateHealedHP(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const;
@ -35,15 +35,14 @@ protected:
class DLL_LINKAGE AntimagicMechanics : public DefaultSpellMechanics class DLL_LINKAGE AntimagicMechanics : public DefaultSpellMechanics
{ {
public: public:
AntimagicMechanics(CSpell * s): DefaultSpellMechanics(s){}; AntimagicMechanics(const CSpell * s);
void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override final; void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override final;
}; };
class DLL_LINKAGE ChainLightningMechanics : public DefaultSpellMechanics class DLL_LINKAGE ChainLightningMechanics : public DefaultSpellMechanics
{ {
public: public:
ChainLightningMechanics(CSpell * s): DefaultSpellMechanics(s){}; ChainLightningMechanics(const CSpell * s);
protected: protected:
std::vector<const CStack *> calculateAffectedStacks(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const override; std::vector<const CStack *> calculateAffectedStacks(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const override;
}; };
@ -51,7 +50,7 @@ protected:
class DLL_LINKAGE CloneMechanics : public DefaultSpellMechanics class DLL_LINKAGE CloneMechanics : public DefaultSpellMechanics
{ {
public: public:
CloneMechanics(CSpell * s): DefaultSpellMechanics(s){}; CloneMechanics(const CSpell * s);
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const override; ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const override;
protected: protected:
void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override; void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
@ -60,11 +59,9 @@ protected:
class DLL_LINKAGE CureMechanics : public HealingSpellMechanics class DLL_LINKAGE CureMechanics : public HealingSpellMechanics
{ {
public: public:
CureMechanics(CSpell * s): HealingSpellMechanics(s){}; CureMechanics(const CSpell * s);
void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override final; void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override final;
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const override; ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const override;
EHealLevel getHealLevel(int effectLevel) const override final; EHealLevel getHealLevel(int effectLevel) const override final;
private: private:
static bool dispellSelector(const Bonus * b); static bool dispellSelector(const Bonus * b);
@ -73,9 +70,8 @@ private:
class DLL_LINKAGE DispellMechanics : public DefaultSpellMechanics class DLL_LINKAGE DispellMechanics : public DefaultSpellMechanics
{ {
public: public:
DispellMechanics(CSpell * s): DefaultSpellMechanics(s){}; DispellMechanics(const CSpell * s);
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const override; ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const override;
void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override final; void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override final;
protected: protected:
void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override; void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
@ -84,7 +80,7 @@ protected:
class DLL_LINKAGE EarthquakeMechanics : public SpecialSpellMechanics class DLL_LINKAGE EarthquakeMechanics : public SpecialSpellMechanics
{ {
public: public:
EarthquakeMechanics(CSpell * s): SpecialSpellMechanics(s){}; EarthquakeMechanics(const CSpell * s);
ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, const ECastingMode::ECastingMode mode, const ISpellCaster * caster) const override; ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, const ECastingMode::ECastingMode mode, const ISpellCaster * caster) const override;
bool requiresCreatureTarget() const override; bool requiresCreatureTarget() const override;
protected: protected:
@ -94,14 +90,14 @@ protected:
class DLL_LINKAGE HypnotizeMechanics : public DefaultSpellMechanics class DLL_LINKAGE HypnotizeMechanics : public DefaultSpellMechanics
{ {
public: public:
HypnotizeMechanics(CSpell * s): DefaultSpellMechanics(s){}; HypnotizeMechanics(const CSpell * s);
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const override; ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const override;
}; };
class DLL_LINKAGE ObstacleMechanics : public SpecialSpellMechanics class DLL_LINKAGE ObstacleMechanics : public SpecialSpellMechanics
{ {
public: public:
ObstacleMechanics(CSpell * s): SpecialSpellMechanics(s){}; ObstacleMechanics(const CSpell * s);
ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const override; ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const override;
protected: protected:
static bool isHexAviable(const CBattleInfoCallback * cb, const BattleHex & hex, const bool mustBeClear); static bool isHexAviable(const CBattleInfoCallback * cb, const BattleHex & hex, const bool mustBeClear);
@ -112,7 +108,7 @@ protected:
class PatchObstacleMechanics : public ObstacleMechanics class PatchObstacleMechanics : public ObstacleMechanics
{ {
public: public:
PatchObstacleMechanics(CSpell * s): ObstacleMechanics(s){}; PatchObstacleMechanics(const CSpell * s);
protected: protected:
void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override; void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
}; };
@ -120,7 +116,7 @@ protected:
class DLL_LINKAGE LandMineMechanics : public PatchObstacleMechanics class DLL_LINKAGE LandMineMechanics : public PatchObstacleMechanics
{ {
public: public:
LandMineMechanics(CSpell * s): PatchObstacleMechanics(s){}; LandMineMechanics(const CSpell * s);
ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, const ECastingMode::ECastingMode mode, const ISpellCaster * caster) const override; ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, const ECastingMode::ECastingMode mode, const ISpellCaster * caster) const override;
bool requiresCreatureTarget() const override; bool requiresCreatureTarget() const override;
protected: protected:
@ -130,7 +126,7 @@ protected:
class DLL_LINKAGE QuicksandMechanics : public PatchObstacleMechanics class DLL_LINKAGE QuicksandMechanics : public PatchObstacleMechanics
{ {
public: public:
QuicksandMechanics(CSpell * s): PatchObstacleMechanics(s){}; QuicksandMechanics(const CSpell * s);
bool requiresCreatureTarget() const override; bool requiresCreatureTarget() const override;
protected: protected:
void setupObstacle(SpellCreatedObstacle * obstacle) const override; void setupObstacle(SpellCreatedObstacle * obstacle) const override;
@ -139,14 +135,14 @@ protected:
class DLL_LINKAGE WallMechanics : public ObstacleMechanics class DLL_LINKAGE WallMechanics : public ObstacleMechanics
{ {
public: public:
WallMechanics(CSpell * s): ObstacleMechanics(s){}; WallMechanics(const CSpell * s);
std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes = nullptr) const override; std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes = nullptr) const override;
}; };
class DLL_LINKAGE FireWallMechanics : public WallMechanics class DLL_LINKAGE FireWallMechanics : public WallMechanics
{ {
public: public:
FireWallMechanics(CSpell * s): WallMechanics(s){}; FireWallMechanics(const CSpell * s);
bool requiresCreatureTarget() const override; bool requiresCreatureTarget() const override;
protected: protected:
void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override; void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
@ -156,7 +152,7 @@ protected:
class DLL_LINKAGE ForceFieldMechanics : public WallMechanics class DLL_LINKAGE ForceFieldMechanics : public WallMechanics
{ {
public: public:
ForceFieldMechanics(CSpell * s): WallMechanics(s){}; ForceFieldMechanics(const CSpell * s);
bool requiresCreatureTarget() const override; bool requiresCreatureTarget() const override;
protected: protected:
void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override; void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
@ -166,7 +162,7 @@ protected:
class DLL_LINKAGE RemoveObstacleMechanics : public SpecialSpellMechanics class DLL_LINKAGE RemoveObstacleMechanics : public SpecialSpellMechanics
{ {
public: public:
RemoveObstacleMechanics(CSpell * s): SpecialSpellMechanics(s){}; RemoveObstacleMechanics(const CSpell * s);
ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, const ECastingMode::ECastingMode mode, const ISpellCaster * caster) const override; ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, const ECastingMode::ECastingMode mode, const ISpellCaster * caster) const override;
ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const override; ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const override;
bool requiresCreatureTarget() const override; bool requiresCreatureTarget() const override;
@ -180,16 +176,14 @@ private:
class DLL_LINKAGE RisingSpellMechanics : public HealingSpellMechanics class DLL_LINKAGE RisingSpellMechanics : public HealingSpellMechanics
{ {
public: public:
RisingSpellMechanics(CSpell * s): HealingSpellMechanics(s){}; RisingSpellMechanics(const CSpell * s);
EHealLevel getHealLevel(int effectLevel) const override; EHealLevel getHealLevel(int effectLevel) const override;
}; };
class DLL_LINKAGE SacrificeMechanics : public RisingSpellMechanics class DLL_LINKAGE SacrificeMechanics : public RisingSpellMechanics
{ {
public: public:
SacrificeMechanics(CSpell * s): RisingSpellMechanics(s){}; SacrificeMechanics(const CSpell * s);
ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, const ECastingMode::ECastingMode mode, const ISpellCaster * caster) const override; ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, const ECastingMode::ECastingMode mode, const ISpellCaster * caster) const override;
bool requiresCreatureTarget() const override; bool requiresCreatureTarget() const override;
protected: protected:
@ -201,7 +195,7 @@ protected:
class DLL_LINKAGE SpecialRisingSpellMechanics : public RisingSpellMechanics class DLL_LINKAGE SpecialRisingSpellMechanics : public RisingSpellMechanics
{ {
public: public:
SpecialRisingSpellMechanics(CSpell * s): RisingSpellMechanics(s){}; SpecialRisingSpellMechanics(const CSpell * s);
ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const override; ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const override;
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const override; ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const override;
}; };
@ -209,8 +203,7 @@ public:
class DLL_LINKAGE SummonMechanics : public SpecialSpellMechanics class DLL_LINKAGE SummonMechanics : public SpecialSpellMechanics
{ {
public: public:
SummonMechanics(CSpell * s, CreatureID cre): SpecialSpellMechanics(s), creatureToSummon(cre){}; SummonMechanics(const CSpell * s, CreatureID cre);
ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, const ECastingMode::ECastingMode mode, const ISpellCaster * caster) const override; ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, const ECastingMode::ECastingMode mode, const ISpellCaster * caster) const override;
bool requiresCreatureTarget() const override; bool requiresCreatureTarget() const override;
protected: protected:
@ -222,8 +215,7 @@ private:
class DLL_LINKAGE TeleportMechanics: public DefaultSpellMechanics class DLL_LINKAGE TeleportMechanics: public DefaultSpellMechanics
{ {
public: public:
TeleportMechanics(CSpell * s): DefaultSpellMechanics(s){}; TeleportMechanics(const CSpell * s);
ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, const ECastingMode::ECastingMode mode, const ISpellCaster * caster) const override; ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, const ECastingMode::ECastingMode mode, const ISpellCaster * caster) const override;
protected: protected:
void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override; void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;

View File

@ -246,6 +246,11 @@ void SpellCastContext::afterCast()
} }
///DefaultSpellMechanics ///DefaultSpellMechanics
DefaultSpellMechanics::DefaultSpellMechanics(const CSpell * s):
ISpellMechanics(s)
{
};
void DefaultSpellMechanics::applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const void DefaultSpellMechanics::applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const
{ {
if (packet->castByHero) if (packet->castByHero)
@ -884,6 +889,12 @@ bool DefaultSpellMechanics::requiresCreatureTarget() const
return true; return true;
} }
///SpecialSpellMechanics
SpecialSpellMechanics::SpecialSpellMechanics(const CSpell * s):
DefaultSpellMechanics(s)
{
}
ESpellCastProblem::ESpellCastProblem SpecialSpellMechanics::canBeCast(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const ESpellCastProblem::ESpellCastProblem SpecialSpellMechanics::canBeCast(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const
{ {
//no problems by default //no problems by default

View File

@ -45,7 +45,7 @@ private:
class DLL_LINKAGE DefaultSpellMechanics : public ISpellMechanics class DLL_LINKAGE DefaultSpellMechanics : public ISpellMechanics
{ {
public: public:
DefaultSpellMechanics(CSpell * s): ISpellMechanics(s){}; DefaultSpellMechanics(const CSpell * s);
std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool * outDroppedHexes = nullptr) const override; std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool * outDroppedHexes = nullptr) const override;
std::vector<const CStack *> getAffectedStacks(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const override final; std::vector<const CStack *> getAffectedStacks(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const override final;
@ -94,7 +94,7 @@ private:
class DLL_LINKAGE SpecialSpellMechanics : public DefaultSpellMechanics class DLL_LINKAGE SpecialSpellMechanics : public DefaultSpellMechanics
{ {
public: public:
SpecialSpellMechanics(CSpell * s): DefaultSpellMechanics(s){}; SpecialSpellMechanics(const CSpell * s);
ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const override; ESpellCastProblem::ESpellCastProblem canBeCast(const CBattleInfoCallback * cb, const SpellTargetingContext & ctx) const override;
protected: protected:

View File

@ -118,7 +118,7 @@ void CSpell::applyBattle(BattleInfo * battle, const BattleSpellCast * packet) co
mechanics->applyBattle(battle, packet); mechanics->applyBattle(battle, packet);
} }
bool CSpell::adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const bool CSpell::adventureCast(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
{ {
assert(env); assert(env);

View File

@ -306,7 +306,7 @@ public:
///Server logic. Has write access to GameState via packets. ///Server logic. Has write access to GameState via packets.
///May be executed on client side by (future) non-cheat-proof scripts. ///May be executed on client side by (future) non-cheat-proof scripts.
bool adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const; bool adventureCast(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const;
void battleCast(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters) const; void battleCast(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters) const;
public: public:

View File

@ -17,6 +17,11 @@
#include "../battle/BattleInfo.h" #include "../battle/BattleInfo.h"
///AcidBreathDamageMechanics ///AcidBreathDamageMechanics
AcidBreathDamageMechanics::AcidBreathDamageMechanics(const CSpell * s):
DefaultSpellMechanics(s)
{
}
void AcidBreathDamageMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const void AcidBreathDamageMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
{ {
//todo: this should be effectValue //todo: this should be effectValue
@ -56,6 +61,11 @@ ESpellCastProblem::ESpellCastProblem AcidBreathDamageMechanics::isImmuneByStack(
} }
///DeathStareMechanics ///DeathStareMechanics
DeathStareMechanics::DeathStareMechanics(const CSpell * s):
DefaultSpellMechanics(s)
{
}
void DeathStareMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const void DeathStareMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
{ {
//calculating dmg to display //calculating dmg to display
@ -80,6 +90,11 @@ void DeathStareMechanics::applyBattleEffects(const SpellCastEnvironment * env, c
} }
///DispellHelpfulMechanics ///DispellHelpfulMechanics
DispellHelpfulMechanics::DispellHelpfulMechanics(const CSpell * s):
DefaultSpellMechanics(s)
{
}
void DispellHelpfulMechanics::applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const void DispellHelpfulMechanics::applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const
{ {
DefaultSpellMechanics::applyBattle(battle, packet); DefaultSpellMechanics::applyBattle(battle, packet);

View File

@ -16,10 +16,8 @@
class DLL_LINKAGE AcidBreathDamageMechanics : public DefaultSpellMechanics class DLL_LINKAGE AcidBreathDamageMechanics : public DefaultSpellMechanics
{ {
public: public:
AcidBreathDamageMechanics(CSpell * s): DefaultSpellMechanics(s){}; AcidBreathDamageMechanics(const CSpell * s);
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const override; ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const override;
protected: protected:
void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override; void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
}; };
@ -27,7 +25,7 @@ protected:
class DLL_LINKAGE DeathStareMechanics : public DefaultSpellMechanics class DLL_LINKAGE DeathStareMechanics : public DefaultSpellMechanics
{ {
public: public:
DeathStareMechanics(CSpell * s): DefaultSpellMechanics(s){}; DeathStareMechanics(const CSpell * s);
protected: protected:
void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override; void applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
}; };
@ -35,10 +33,8 @@ protected:
class DLL_LINKAGE DispellHelpfulMechanics : public DefaultSpellMechanics class DLL_LINKAGE DispellHelpfulMechanics : public DefaultSpellMechanics
{ {
public: public:
DispellHelpfulMechanics(CSpell * s): DefaultSpellMechanics(s){}; DispellHelpfulMechanics(const CSpell * s);
void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override final; void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override final;
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const override; ESpellCastProblem::ESpellCastProblem isImmuneByStack(const ISpellCaster * caster, const CStack * obj) const override;
private: private:
static bool positiveSpellEffects(const Bonus * b); static bool positiveSpellEffects(const Bonus * b);

View File

@ -113,13 +113,12 @@ int BattleSpellCastParameters::getEffectValue() const
} }
///ISpellMechanics ///ISpellMechanics
ISpellMechanics::ISpellMechanics(CSpell * s): ISpellMechanics::ISpellMechanics(const CSpell * s):
owner(s) owner(s)
{ {
} }
std::unique_ptr<ISpellMechanics> ISpellMechanics::createMechanics(CSpell * s) std::unique_ptr<ISpellMechanics> ISpellMechanics::createMechanics(const CSpell * s)
{ {
switch (s->id) switch (s->id)
{ {
@ -174,13 +173,12 @@ std::unique_ptr<ISpellMechanics> ISpellMechanics::createMechanics(CSpell * s)
} }
//IAdventureSpellMechanics //IAdventureSpellMechanics
IAdventureSpellMechanics::IAdventureSpellMechanics(CSpell * s): IAdventureSpellMechanics::IAdventureSpellMechanics(const CSpell * s):
owner(s) owner(s)
{ {
} }
std::unique_ptr<IAdventureSpellMechanics> IAdventureSpellMechanics::createMechanics(CSpell * s) std::unique_ptr<IAdventureSpellMechanics> IAdventureSpellMechanics::createMechanics(const CSpell * s)
{ {
switch (s->id) switch (s->id)
{ {

View File

@ -13,6 +13,7 @@
#include "CSpellHandler.h" #include "CSpellHandler.h"
#include "../battle/BattleHex.h" #include "../battle/BattleHex.h"
struct Query;
///callback to be provided by server ///callback to be provided by server
class DLL_LINKAGE SpellCastEnvironment class DLL_LINKAGE SpellCastEnvironment
@ -27,7 +28,9 @@ public:
virtual const CMap * getMap() const = 0; virtual const CMap * getMap() const = 0;
virtual const CGameInfoCallback * getCb() const = 0; virtual const CGameInfoCallback * getCb() const = 0;
virtual bool moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, PlayerColor asker = PlayerColor::NEUTRAL) const =0; //TODO: remove virtual bool moveHero(ObjectInstanceID hid, int3 dst, bool teleporting) const = 0; //TODO: remove
virtual void genericQuery(Query * request, PlayerColor color, std::function<void(const JsonNode &)> callback) const = 0;//TODO: type safety on query, use generic query packet when implemented
}; };
///all parameters of particular cast event ///all parameters of particular cast event
@ -101,13 +104,12 @@ struct DLL_LINKAGE SpellTargetingContext
SpellTargetingContext(const CSpell * s, ECastingMode::ECastingMode mode_, const ISpellCaster * caster_, int schoolLvl_, BattleHex destination_) SpellTargetingContext(const CSpell * s, ECastingMode::ECastingMode mode_, const ISpellCaster * caster_, int schoolLvl_, BattleHex destination_)
: ti(s,schoolLvl_, mode_), mode(mode_), destination(destination_), caster(caster_), schoolLvl(schoolLvl_) : ti(s,schoolLvl_, mode_), mode(mode_), destination(destination_), caster(caster_), schoolLvl(schoolLvl_)
{}; {};
}; };
class DLL_LINKAGE ISpellMechanics class DLL_LINKAGE ISpellMechanics
{ {
public: public:
ISpellMechanics(CSpell * s); ISpellMechanics(const CSpell * s);
virtual ~ISpellMechanics(){}; virtual ~ISpellMechanics(){};
virtual std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool * outDroppedHexes = nullptr) const = 0; virtual std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool * outDroppedHexes = nullptr) const = 0;
@ -125,9 +127,9 @@ public:
//if true use generic algorithm for target existence check, see CSpell::canBeCast //if true use generic algorithm for target existence check, see CSpell::canBeCast
virtual bool requiresCreatureTarget() const = 0; virtual bool requiresCreatureTarget() const = 0;
static std::unique_ptr<ISpellMechanics> createMechanics(CSpell * s); static std::unique_ptr<ISpellMechanics> createMechanics(const CSpell * s);
protected: protected:
CSpell * owner; const CSpell * owner;
}; };
struct DLL_LINKAGE AdventureSpellCastParameters struct DLL_LINKAGE AdventureSpellCastParameters
@ -139,12 +141,12 @@ struct DLL_LINKAGE AdventureSpellCastParameters
class DLL_LINKAGE IAdventureSpellMechanics class DLL_LINKAGE IAdventureSpellMechanics
{ {
public: public:
IAdventureSpellMechanics(CSpell * s); IAdventureSpellMechanics(const CSpell * s);
virtual ~IAdventureSpellMechanics() = default; virtual ~IAdventureSpellMechanics() = default;
virtual bool adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const = 0; virtual bool adventureCast(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const = 0;
static std::unique_ptr<IAdventureSpellMechanics> createMechanics(CSpell * s); static std::unique_ptr<IAdventureSpellMechanics> createMechanics(const CSpell * s);
protected: protected:
CSpell * owner; const CSpell * owner;
}; };

View File

@ -71,7 +71,8 @@ public:
void complain(const std::string & problem) const override; void complain(const std::string & problem) const override;
const CMap * getMap() const override; const CMap * getMap() const override;
const CGameInfoCallback * getCb() const override; const CGameInfoCallback * getCb() const override;
bool moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, PlayerColor asker = PlayerColor::NEUTRAL) const override; bool moveHero(ObjectInstanceID hid, int3 dst, bool teleporting) const override;
void genericQuery(Query * request, PlayerColor color, std::function<void(const JsonNode &)> callback) const override;
private: private:
mutable CGameHandler * gh; mutable CGameHandler * gh;
}; };
@ -310,7 +311,7 @@ void CGameHandler::levelUpHero(const CGHeroInstance * hero)
} }
else if (hlu.skills.size() > 1) else if (hlu.skills.size() > 1)
{ {
auto levelUpQuery = std::make_shared<CHeroLevelUpDialogQuery>(hlu); auto levelUpQuery = std::make_shared<CHeroLevelUpDialogQuery>(this, hlu);
hlu.queryID = levelUpQuery->queryID; hlu.queryID = levelUpQuery->queryID;
queries.addQuery(levelUpQuery); queries.addQuery(levelUpQuery);
sendAndApply(&hlu); sendAndApply(&hlu);
@ -448,7 +449,7 @@ void CGameHandler::levelUpCommander(const CCommanderInstance * c)
} }
else if (skillAmount > 1) //apply and ask for secondary skill else if (skillAmount > 1) //apply and ask for secondary skill
{ {
auto commanderLevelUp = std::make_shared<CCommanderLevelUpDialogQuery>(clu); auto commanderLevelUp = std::make_shared<CCommanderLevelUpDialogQuery>(this, clu);
clu.queryID = commanderLevelUp->queryID; clu.queryID = commanderLevelUp->queryID;
queries.addQuery(commanderLevelUp); queries.addQuery(commanderLevelUp);
sendAndApply(&clu); sendAndApply(&clu);
@ -1438,7 +1439,6 @@ CGameHandler::CGameHandler(void)
applier = new CApplier<CBaseForGHApply>; applier = new CApplier<CBaseForGHApply>;
registerTypesServerPacks(*applier); registerTypesServerPacks(*applier);
visitObjectAfterVictory = false; visitObjectAfterVictory = false;
queries.gh = this;
spellEnv = new ServerSpellCastEnvironment(this); spellEnv = new ServerSpellCastEnvironment(this);
} }
@ -2144,7 +2144,7 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, boo
{ {
LOG_TRACE_PARAMS(logGlobal, "Hero %s starts movement from %s to %s", h->name % tmh.start % tmh.end); LOG_TRACE_PARAMS(logGlobal, "Hero %s starts movement from %s to %s", h->name % tmh.start % tmh.end);
auto moveQuery = std::make_shared<CHeroMovementQuery>(tmh, h); auto moveQuery = std::make_shared<CHeroMovementQuery>(this, tmh, h);
queries.addQuery(moveQuery); queries.addQuery(moveQuery);
if (leavingTile == LEAVING_TILE) if (leavingTile == LEAVING_TILE)
@ -2317,7 +2317,7 @@ void CGameHandler::setOwner(const CGObjectInstance * obj, PlayerColor owner)
void CGameHandler::showBlockingDialog(BlockingDialog *iw) void CGameHandler::showBlockingDialog(BlockingDialog *iw)
{ {
auto dialogQuery = std::make_shared<CBlockingDialogQuery>(*iw); auto dialogQuery = std::make_shared<CBlockingDialogQuery>(this, *iw);
queries.addQuery(dialogQuery); queries.addQuery(dialogQuery);
iw->queryID = dialogQuery->queryID; iw->queryID = dialogQuery->queryID;
sendToAllClients(iw); sendToAllClients(iw);
@ -2325,7 +2325,7 @@ void CGameHandler::showBlockingDialog(BlockingDialog *iw)
void CGameHandler::showTeleportDialog(TeleportDialog *iw) void CGameHandler::showTeleportDialog(TeleportDialog *iw)
{ {
auto dialogQuery = std::make_shared<CTeleportDialogQuery>(*iw); auto dialogQuery = std::make_shared<CTeleportDialogQuery>(this, *iw);
queries.addQuery(dialogQuery); queries.addQuery(dialogQuery);
iw->queryID = dialogQuery->queryID; iw->queryID = dialogQuery->queryID;
sendToAllClients(iw); sendToAllClients(iw);
@ -2453,7 +2453,7 @@ void CGameHandler::startBattlePrimary(const CArmedInstance *army1, const CArmedI
setupBattle(tile, armies, heroes, creatureBank, town); //initializes stacks, places creatures on battlefield, blocks and informs player interfaces setupBattle(tile, armies, heroes, creatureBank, town); //initializes stacks, places creatures on battlefield, blocks and informs player interfaces
auto battleQuery = std::make_shared<CBattleQuery>(gs->curB); auto battleQuery = std::make_shared<CBattleQuery>(this, gs->curB);
queries.addQuery(battleQuery); queries.addQuery(battleQuery);
boost::thread(&CGameHandler::runBattle, this); boost::thread(&CGameHandler::runBattle, this);
@ -2620,7 +2620,7 @@ void CGameHandler::heroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2)
if (getPlayerRelations(h1->getOwner(), h2->getOwner())) if (getPlayerRelations(h1->getOwner(), h2->getOwner()))
{ {
auto exchange = std::make_shared<CGarrisonDialogQuery>(h1, h2); auto exchange = std::make_shared<CGarrisonDialogQuery>(this, h1, h2);
ExchangeDialog hex; ExchangeDialog hex;
hex.queryID = exchange->queryID; hex.queryID = exchange->queryID;
hex.heroes[0] = getHero(hero1); hex.heroes[0] = getHero(hero1);
@ -3735,20 +3735,19 @@ bool CGameHandler::hireHero(const CGObjectInstance *obj, ui8 hid, PlayerColor pl
return true; return true;
} }
bool CGameHandler::queryReply(QueryID qid, ui32 answer, PlayerColor player) bool CGameHandler::queryReply(QueryID qid, const JsonNode & answer, PlayerColor player)
{ {
boost::unique_lock<boost::recursive_mutex> lock(gsm); boost::unique_lock<boost::recursive_mutex> lock(gsm);
logGlobal->trace("Player %s attempts answering query %d with answer %d", player, qid, answer); logGlobal->trace("Player %s attempts answering query %d with answer:", player, qid);
logGlobal->traceStream() << answer;
auto topQuery = queries.topQuery(player); auto topQuery = queries.topQuery(player);
COMPLAIN_RET_FALSE_IF(!topQuery, "This player doesn't have any queries!"); COMPLAIN_RET_FALSE_IF(!topQuery, "This player doesn't have any queries!");
COMPLAIN_RET_FALSE_IF(topQuery->queryID != qid, "This player top query has different ID!"); COMPLAIN_RET_FALSE_IF(topQuery->queryID != qid, "This player top query has different ID!");
COMPLAIN_RET_FALSE_IF(!topQuery->endsByPlayerAnswer(), "This query cannot be ended by player's answer!"); COMPLAIN_RET_FALSE_IF(!topQuery->endsByPlayerAnswer(), "This query cannot be ended by player's answer!");
if (auto dialogQuery = std::dynamic_pointer_cast<CDialogQuery>(topQuery)) topQuery->setReply(answer);
dialogQuery->answer = answer;
queries.popQuery(topQuery); queries.popQuery(topQuery);
return true; return true;
} }
@ -4853,7 +4852,7 @@ void CGameHandler::showGarrisonDialog(ObjectInstanceID upobj, ObjectInstanceID h
assert(lowerArmy); assert(lowerArmy);
assert(upperArmy); assert(upperArmy);
auto garrisonQuery = std::make_shared<CGarrisonDialogQuery>(upperArmy, lowerArmy); auto garrisonQuery = std::make_shared<CGarrisonDialogQuery>(this, upperArmy, lowerArmy);
queries.addQuery(garrisonQuery); queries.addQuery(garrisonQuery);
GarrisonDialog gd; GarrisonDialog gd;
@ -4924,7 +4923,7 @@ bool CGameHandler::isAllowedExchange(ObjectInstanceID id1, ObjectInstanceID id2)
void CGameHandler::objectVisited(const CGObjectInstance * obj, const CGHeroInstance * h) void CGameHandler::objectVisited(const CGObjectInstance * obj, const CGHeroInstance * h)
{ {
logGlobal->debug("%s visits %s (%d:%d)", h->nodeName(), obj->getObjectName(), obj->ID, obj->subID); logGlobal->debug("%s visits %s (%d:%d)", h->nodeName(), obj->getObjectName(), obj->ID, obj->subID);
auto visitQuery = std::make_shared<CObjectVisitQuery>(obj, h, obj->visitablePos()); auto visitQuery = std::make_shared<CObjectVisitQuery>(this, obj, h, obj->visitablePos());
queries.addQuery(visitQuery); //TODO real visit pos queries.addQuery(visitQuery); //TODO real visit pos
HeroVisit hv; HeroVisit hv;
@ -5409,17 +5408,6 @@ void CGameHandler::handleAfterAttackCasting(const BattleAttack & bat)
} }
} }
bool CGameHandler::castSpell(const CGHeroInstance *h, SpellID spellID, const int3 &pos)
{
const CSpell *s = spellID.toSpell();
AdventureSpellCastParameters p;
p.caster = h;
p.pos = pos;
return s->adventureCast(spellEnv, p);
}
void CGameHandler::visitObjectOnTile(const TerrainTile &t, const CGHeroInstance * h) void CGameHandler::visitObjectOnTile(const TerrainTile &t, const CGHeroInstance * h)
{ {
if (!t.visitableObjects.empty()) if (!t.visitableObjects.empty())
@ -6533,13 +6521,20 @@ const CGameInfoCallback * ServerSpellCastEnvironment::getCb() const
return gh; return gh;
} }
const CMap * ServerSpellCastEnvironment::getMap() const const CMap * ServerSpellCastEnvironment::getMap() const
{ {
return gh->gameState()->map; return gh->gameState()->map;
} }
bool ServerSpellCastEnvironment::moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, PlayerColor asker) const bool ServerSpellCastEnvironment::moveHero(ObjectInstanceID hid, int3 dst, bool teleporting) const
{ {
return gh->moveHero(hid, dst, teleporting, false, asker); return gh->moveHero(hid, dst, teleporting, false);
}
void ServerSpellCastEnvironment::genericQuery(Query * request, PlayerColor color, std::function<void(const JsonNode&)> callback) const
{
auto query = std::make_shared<CGenericQuery>(&gh->queries, color, callback);
request->queryID = query->queryID;
gh->queries.addQuery(query);
gh->sendAndApply(request);
} }

View File

@ -31,7 +31,7 @@ struct NewStructures;
class CGHeroInstance; class CGHeroInstance;
class IMarket; class IMarket;
class ServerSpellCastEnvironment; class SpellCastEnvironment;
struct PlayerStatus struct PlayerStatus
{ {
@ -92,6 +92,8 @@ public:
ui32 QID; ui32 QID;
Queries queries; Queries queries;
SpellCastEnvironment * spellEnv;
bool isValidObject(const CGObjectInstance *obj) const; bool isValidObject(const CGObjectInstance *obj) const;
bool isBlockedByQueries(const CPack *pack, PlayerColor player); bool isBlockedByQueries(const CPack *pack, PlayerColor player);
bool isAllowedExchange(ObjectInstanceID id1, ObjectInstanceID id2); bool isAllowedExchange(ObjectInstanceID id1, ObjectInstanceID id2);
@ -199,7 +201,7 @@ public:
void stackTurnTrigger(const CStack *stack); void stackTurnTrigger(const CStack *stack);
void handleDamageFromObstacle(const CObstacleInstance &obstacle, const CStack * curStack); //checks if obstacle is land mine and handles possible consequences void handleDamageFromObstacle(const CObstacleInstance &obstacle, const CStack * curStack); //checks if obstacle is land mine and handles possible consequences
void removeObstacle(const CObstacleInstance &obstacle); void removeObstacle(const CObstacleInstance &obstacle);
bool queryReply( QueryID qid, ui32 answer, PlayerColor player ); bool queryReply( QueryID qid, const JsonNode & answer, PlayerColor player );
bool hireHero( const CGObjectInstance *obj, ui8 hid, PlayerColor player ); bool hireHero( const CGObjectInstance *obj, ui8 hid, PlayerColor player );
bool buildBoat( ObjectInstanceID objid ); bool buildBoat( ObjectInstanceID objid );
bool setFormation( ObjectInstanceID hid, ui8 formation ); bool setFormation( ObjectInstanceID hid, ui8 formation );
@ -231,7 +233,6 @@ public:
void objectVisitEnded(const CObjectVisitQuery &query); void objectVisitEnded(const CObjectVisitQuery &query);
void engageIntoBattle( PlayerColor player ); void engageIntoBattle( PlayerColor player );
bool dig(const CGHeroInstance *h); bool dig(const CGHeroInstance *h);
bool castSpell(const CGHeroInstance *h, SpellID spellID, const int3 &pos);
void moveArmy(const CArmedInstance *src, const CArmedInstance *dst, bool allowMerging); void moveArmy(const CArmedInstance *src, const CArmedInstance *dst, bool allowMerging);
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
@ -257,7 +258,6 @@ public:
FinishingBattleHelper(); FinishingBattleHelper();
FinishingBattleHelper(std::shared_ptr<const CBattleQuery> Query, int RemainingBattleQueriesCount); FinishingBattleHelper(std::shared_ptr<const CBattleQuery> Query, int RemainingBattleQueriesCount);
//std::shared_ptr<const CBattleQuery> query;
const CGHeroInstance *winnerHero, *loserHero; const CGHeroInstance *winnerHero, *loserHero;
PlayerColor victor, loser; PlayerColor victor, loser;
@ -265,7 +265,7 @@ public:
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
h & /*query & */winnerHero & loserHero & victor & loser; h & winnerHero & loserHero & victor & loser;
if(version < 774 && !h.saving) if(version < 774 && !h.saving)
{ {
bool duel; bool duel;
@ -292,8 +292,6 @@ public:
CRandomGenerator & getRandomGenerator(); CRandomGenerator & getRandomGenerator();
private: private:
ServerSpellCastEnvironment * spellEnv;
std::list<PlayerColor> generatePlayerTurnOrder() const; std::list<PlayerColor> generatePlayerTurnOrder() const;
void makeStackDoNothing(const CStack * next); void makeStackDoNothing(const CStack * next);
void getVictoryLossMessage(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult, InfoWindow & out) const; void getVictoryLossMessage(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult, InfoWindow & out) const;

View File

@ -7,7 +7,7 @@
boost::mutex Queries::mx; boost::mutex Queries::mx;
template <typename Container> template <typename Container>
std::string formatContainer(const Container &c, std::string delimeter=", ", std::string opener="(", std::string closer=")") std::string formatContainer(const Container & c, std::string delimeter = ", ", std::string opener = "(", std::string closer=")")
{ {
std::string ret = opener; std::string ret = opener;
auto itr = std::begin(c); auto itr = std::begin(c);
@ -24,17 +24,18 @@ std::string formatContainer(const Container &c, std::string delimeter=", ", std:
return ret; return ret;
} }
std::ostream & operator<<(std::ostream &out, const CQuery &query) std::ostream & operator<<(std::ostream & out, const CQuery & query)
{ {
return out << query.toString(); return out << query.toString();
} }
std::ostream & operator<<(std::ostream &out, QueryPtr query) std::ostream & operator<<(std::ostream & out, QueryPtr query)
{ {
return out << "[" << query.get() << "] " << query->toString(); return out << "[" << query.get() << "] " << query->toString();
} }
CQuery::CQuery(void) CQuery::CQuery(Queries * Owner):
owner(Owner)
{ {
boost::unique_lock<boost::mutex> l(Queries::mx); boost::unique_lock<boost::mutex> l(Queries::mx);
@ -53,9 +54,7 @@ CQuery::~CQuery(void)
void CQuery::addPlayer(PlayerColor color) void CQuery::addPlayer(PlayerColor color)
{ {
if(color.isValidPlayer()) if(color.isValidPlayer())
{
players.push_back(color); players.push_back(color);
}
} }
std::string CQuery::toString() const std::string CQuery::toString() const
@ -69,31 +68,59 @@ bool CQuery::endsByPlayerAnswer() const
return false; return false;
} }
void CQuery::onRemoval(CGameHandler *gh, PlayerColor color) void CQuery::onRemoval(PlayerColor color)
{ {
} }
bool CQuery::blocksPack(const CPack *pack) const bool CQuery::blocksPack(const CPack * pack) const
{ {
return false; return false;
} }
void CQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const void CQuery::notifyObjectAboutRemoval(const CObjectVisitQuery & objectVisit) const
{
}
void CQuery::onExposure(CGameHandler *gh, QueryPtr topQuery)
{
gh->queries.popQuery(*this);
}
void CQuery::onAdding(CGameHandler *gh, PlayerColor color)
{ {
} }
CObjectVisitQuery::CObjectVisitQuery(const CGObjectInstance *Obj, const CGHeroInstance *Hero, int3 Tile) void CQuery::onExposure(QueryPtr topQuery)
: visitedObject(Obj), visitingHero(Hero), tile(Tile), removeObjectAfterVisit(false) {
logGlobal->trace("Exposed query with id %d", queryID);
owner->popQuery(*this);
}
void CQuery::onAdding(PlayerColor color)
{
}
void CQuery::onAdded(PlayerColor color)
{
}
void CQuery::setReply(const JsonNode & reply)
{
}
bool CQuery::blockAllButReply(const CPack * pack) const
{
//We accept only query replies from correct player
if(auto reply = dynamic_ptr_cast<QueryReply>(pack))
return !vstd::contains(players, reply->player);
return true;
}
CGhQuery::CGhQuery(CGameHandler * owner):
CQuery(&owner->queries), gh(owner)
{
}
CObjectVisitQuery::CObjectVisitQuery(CGameHandler * owner, const CGObjectInstance * Obj, const CGHeroInstance * Hero, int3 Tile):
CGhQuery(owner), visitedObject(Obj), visitingHero(Hero), tile(Tile), removeObjectAfterVisit(false)
{ {
addPlayer(Hero->tempOwner); addPlayer(Hero->tempOwner);
} }
@ -105,7 +132,7 @@ bool CObjectVisitQuery::blocksPack(const CPack *pack) const
return true; return true;
} }
void CObjectVisitQuery::onRemoval(CGameHandler *gh, PlayerColor color) void CObjectVisitQuery::onRemoval(PlayerColor color)
{ {
gh->objectVisitEnded(*this); gh->objectVisitEnded(*this);
@ -115,13 +142,13 @@ void CObjectVisitQuery::onRemoval(CGameHandler *gh, PlayerColor color)
gh->removeObject(visitedObject); gh->removeObject(visitedObject);
} }
void CObjectVisitQuery::onExposure(CGameHandler *gh, QueryPtr topQuery) void CObjectVisitQuery::onExposure(QueryPtr topQuery)
{ {
//Object may have been removed and deleted. //Object may have been removed and deleted.
if(gh->isValidObject(visitedObject)) if(gh->isValidObject(visitedObject))
topQuery->notifyObjectAboutRemoval(*this); topQuery->notifyObjectAboutRemoval(*this);
gh->queries.popQuery(*this); owner->popQuery(*this);
} }
void Queries::popQuery(PlayerColor player, QueryPtr query) void Queries::popQuery(PlayerColor player, QueryPtr query)
@ -136,13 +163,11 @@ void Queries::popQuery(PlayerColor player, QueryPtr query)
queries[player] -= query; queries[player] -= query;
auto nextQuery = topQuery(player); auto nextQuery = topQuery(player);
query->onRemoval(gh, player); query->onRemoval(player);
//Exposure on query below happens only if removal didn't trigger any new query //Exposure on query below happens only if removal didn't trigger any new query
if(nextQuery && nextQuery == topQuery(player)) if(nextQuery && nextQuery == topQuery(player))
{ nextQuery->onExposure(query);
nextQuery->onExposure(gh, query);
}
} }
void Queries::popQuery(const CQuery &query) void Queries::popQuery(const CQuery &query)
@ -170,12 +195,15 @@ void Queries::addQuery(QueryPtr query)
{ {
for(auto player : query->players) for(auto player : query->players)
addQuery(player, query); addQuery(player, query);
for(auto player : query->players)
query->onAdded(player);
} }
void Queries::addQuery(PlayerColor player, QueryPtr query) void Queries::addQuery(PlayerColor player, QueryPtr query)
{ {
//LOG_TRACE_PARAMS(logGlobal, "player='%d', query='%s'", player.getNum() % query); //LOG_TRACE_PARAMS(logGlobal, "player='%d', query='%s'", player.getNum() % query);
query->onAdding(gh, player); query->onAdding(player);
queries[player].push_back(query); queries[player].push_back(query);
} }
@ -193,7 +221,7 @@ void Queries::popIfTop(QueryPtr query)
popIfTop(*query); popIfTop(*query);
} }
void Queries::popIfTop(const CQuery &query) void Queries::popIfTop(const CQuery & query)
{ {
for(PlayerColor color : query.players) for(PlayerColor color : query.players)
if(topQuery(color).get() == &query) if(topQuery(color).get() == &query)
@ -203,8 +231,8 @@ void Queries::popIfTop(const CQuery &query)
std::vector<std::shared_ptr<const CQuery>> Queries::allQueries() const std::vector<std::shared_ptr<const CQuery>> Queries::allQueries() const
{ {
std::vector<std::shared_ptr<const CQuery>> ret; std::vector<std::shared_ptr<const CQuery>> ret;
for(auto &playerQueries : queries) for(auto & playerQueries : queries)
for(auto &query : playerQueries.second) for(auto & query : playerQueries.second)
ret.push_back(query); ret.push_back(query);
return ret; return ret;
@ -214,53 +242,55 @@ std::vector<std::shared_ptr<CQuery>> Queries::allQueries()
{ {
//TODO code duplication with const function :( //TODO code duplication with const function :(
std::vector<std::shared_ptr<CQuery>> ret; std::vector<std::shared_ptr<CQuery>> ret;
for(auto &playerQueries : queries) for(auto & playerQueries : queries)
for(auto &query : playerQueries.second) for(auto & query : playerQueries.second)
ret.push_back(query); ret.push_back(query);
return ret; return ret;
} }
void CBattleQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const void CBattleQuery::notifyObjectAboutRemoval(const CObjectVisitQuery & objectVisit) const
{ {
assert(result); assert(result);
objectVisit.visitedObject->battleFinished(objectVisit.visitingHero, *result); objectVisit.visitedObject->battleFinished(objectVisit.visitingHero, *result);
} }
CBattleQuery::CBattleQuery(const BattleInfo *Bi) CBattleQuery::CBattleQuery(CGameHandler * owner, const BattleInfo * Bi):
CGhQuery(owner)
{ {
belligerents[0] = Bi->sides[0].armyObject; belligerents[0] = Bi->sides[0].armyObject;
belligerents[1] = Bi->sides[1].armyObject; belligerents[1] = Bi->sides[1].armyObject;
bi = Bi; bi = Bi;
for(auto &side : bi->sides) for(auto & side : bi->sides)
addPlayer(side.color); addPlayer(side.color);
} }
CBattleQuery::CBattleQuery() CBattleQuery::CBattleQuery(CGameHandler * owner):
:bi(nullptr) CGhQuery(owner), bi(nullptr)
{ {
belligerents[0] = belligerents[1] = nullptr; belligerents[0] = belligerents[1] = nullptr;
} }
bool CBattleQuery::blocksPack(const CPack *pack) const bool CBattleQuery::blocksPack(const CPack * pack) const
{ {
const char * name = typeid(*pack).name(); const char * name = typeid(*pack).name();
return strcmp(name, typeid(MakeAction).name()) && strcmp(name, typeid(MakeCustomAction).name()); return strcmp(name, typeid(MakeAction).name()) && strcmp(name, typeid(MakeCustomAction).name());
} }
void CBattleQuery::onRemoval(CGameHandler *gh, PlayerColor color) void CBattleQuery::onRemoval(PlayerColor color)
{ {
gh->battleAfterLevelUp(*result); gh->battleAfterLevelUp(*result);
} }
void CGarrisonDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const void CGarrisonDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery & objectVisit) const
{ {
objectVisit.visitedObject->garrisonDialogClosed(objectVisit.visitingHero); objectVisit.visitedObject->garrisonDialogClosed(objectVisit.visitingHero);
} }
CGarrisonDialogQuery::CGarrisonDialogQuery(const CArmedInstance *up, const CArmedInstance *down) CGarrisonDialogQuery::CGarrisonDialogQuery(CGameHandler * owner, const CArmedInstance * up, const CArmedInstance * down):
CDialogQuery(owner)
{ {
exchangingArmies[0] = up; exchangingArmies[0] = up;
exchangingArmies[1] = down; exchangingArmies[1] = down;
@ -269,18 +299,16 @@ CGarrisonDialogQuery::CGarrisonDialogQuery(const CArmedInstance *up, const CArme
addPlayer(down->tempOwner); addPlayer(down->tempOwner);
} }
bool CGarrisonDialogQuery::blocksPack(const CPack *pack) const bool CGarrisonDialogQuery::blocksPack(const CPack * pack) const
{ {
std::set<ObjectInstanceID> ourIds; std::set<ObjectInstanceID> ourIds;
ourIds.insert(this->exchangingArmies[0]->id); ourIds.insert(this->exchangingArmies[0]->id);
ourIds.insert(this->exchangingArmies[1]->id); ourIds.insert(this->exchangingArmies[1]->id);
if (auto stacks = dynamic_ptr_cast<ArrangeStacks>(pack)) if(auto stacks = dynamic_ptr_cast<ArrangeStacks>(pack))
{
return !vstd::contains(ourIds, stacks->id1) || !vstd::contains(ourIds, stacks->id2); return !vstd::contains(ourIds, stacks->id1) || !vstd::contains(ourIds, stacks->id2);
}
if (auto arts = dynamic_ptr_cast<ExchangeArtifacts>(pack)) if(auto arts = dynamic_ptr_cast<ExchangeArtifacts>(pack))
{ {
if(auto id1 = boost::apply_visitor(GetEngagedHeroIds(), arts->src.artHolder)) if(auto id1 = boost::apply_visitor(GetEngagedHeroIds(), arts->src.artHolder))
if(!vstd::contains(ourIds, *id1)) if(!vstd::contains(ourIds, *id1))
@ -291,36 +319,32 @@ bool CGarrisonDialogQuery::blocksPack(const CPack *pack) const
return true; return true;
return false; return false;
} }
if (auto dismiss = dynamic_ptr_cast<DisbandCreature>(pack)) if(auto dismiss = dynamic_ptr_cast<DisbandCreature>(pack))
{
return !vstd::contains(ourIds, dismiss->id); return !vstd::contains(ourIds, dismiss->id);
}
if (auto dismiss = dynamic_ptr_cast<AssembleArtifacts>(pack)) if(auto dismiss = dynamic_ptr_cast<AssembleArtifacts>(pack))
{
return !vstd::contains(ourIds, dismiss->heroID); return !vstd::contains(ourIds, dismiss->heroID);
}
if(auto upgrade = dynamic_ptr_cast<UpgradeCreature>(pack)) if(auto upgrade = dynamic_ptr_cast<UpgradeCreature>(pack))
{
return !vstd::contains(ourIds, upgrade->id); return !vstd::contains(ourIds, upgrade->id);
}
return CDialogQuery::blocksPack(pack); return CDialogQuery::blocksPack(pack);
} }
void CBlockingDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const void CBlockingDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery & objectVisit) const
{ {
assert(answer); assert(answer);
objectVisit.visitedObject->blockingDialogAnswered(objectVisit.visitingHero, *answer); objectVisit.visitedObject->blockingDialogAnswered(objectVisit.visitingHero, *answer);
} }
CBlockingDialogQuery::CBlockingDialogQuery(const BlockingDialog &bd) CBlockingDialogQuery::CBlockingDialogQuery(CGameHandler * owner, const BlockingDialog & bd):
CDialogQuery(owner)
{ {
this->bd = bd; this->bd = bd;
addPlayer(bd.player); addPlayer(bd.player);
} }
void CTeleportDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const void CTeleportDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery & objectVisit) const
{ {
// do not change to dynamic_ptr_cast - SIGSEGV! // do not change to dynamic_ptr_cast - SIGSEGV!
auto obj = dynamic_cast<const CGTeleport*>(objectVisit.visitedObject); auto obj = dynamic_cast<const CGTeleport*>(objectVisit.visitedObject);
@ -330,71 +354,80 @@ void CTeleportDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &obj
logGlobal->error("Invalid instance in teleport query"); logGlobal->error("Invalid instance in teleport query");
} }
CTeleportDialogQuery::CTeleportDialogQuery(const TeleportDialog &td) CTeleportDialogQuery::CTeleportDialogQuery(CGameHandler * owner, const TeleportDialog & td):
CDialogQuery(owner)
{ {
this->td = td; this->td = td;
addPlayer(td.hero->tempOwner); addPlayer(td.hero->tempOwner);
} }
CHeroLevelUpDialogQuery::CHeroLevelUpDialogQuery(const HeroLevelUp &Hlu) CHeroLevelUpDialogQuery::CHeroLevelUpDialogQuery(CGameHandler * owner, const HeroLevelUp & Hlu):
CDialogQuery(owner)
{ {
hlu = Hlu; hlu = Hlu;
addPlayer(hlu.hero->tempOwner); addPlayer(hlu.hero->tempOwner);
} }
void CHeroLevelUpDialogQuery::onRemoval(CGameHandler *gh, PlayerColor color) void CHeroLevelUpDialogQuery::onRemoval(PlayerColor color)
{ {
assert(answer); assert(answer);
logGlobal->trace("Completing hero level-up query. %s gains skill %d", hlu.hero->getObjectName(), answer.get()); logGlobal->trace("Completing hero level-up query. %s gains skill %d", hlu.hero->getObjectName(), answer.get());
gh->levelUpHero(hlu.hero, hlu.skills[*answer]); gh->levelUpHero(hlu.hero, hlu.skills[*answer]);
} }
void CHeroLevelUpDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const void CHeroLevelUpDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery & objectVisit) const
{ {
objectVisit.visitedObject->heroLevelUpDone(objectVisit.visitingHero); objectVisit.visitedObject->heroLevelUpDone(objectVisit.visitingHero);
} }
CCommanderLevelUpDialogQuery::CCommanderLevelUpDialogQuery(const CommanderLevelUp &Clu) CCommanderLevelUpDialogQuery::CCommanderLevelUpDialogQuery(CGameHandler * owner, const CommanderLevelUp & Clu):
CDialogQuery(owner)
{ {
clu = Clu; clu = Clu;
addPlayer(clu.hero->tempOwner); addPlayer(clu.hero->tempOwner);
} }
void CCommanderLevelUpDialogQuery::onRemoval(CGameHandler *gh, PlayerColor color) void CCommanderLevelUpDialogQuery::onRemoval(PlayerColor color)
{ {
assert(answer); assert(answer);
logGlobal->trace("Completing commander level-up query. Commander of hero %s gains skill %s", clu.hero->getObjectName(), answer.get()); logGlobal->trace("Completing commander level-up query. Commander of hero %s gains skill %s", clu.hero->getObjectName(), answer.get());
gh->levelUpCommander(clu.hero->commander, clu.skills[*answer]); gh->levelUpCommander(clu.hero->commander, clu.skills[*answer]);
} }
void CCommanderLevelUpDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const void CCommanderLevelUpDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery & objectVisit) const
{ {
objectVisit.visitedObject->heroLevelUpDone(objectVisit.visitingHero); objectVisit.visitedObject->heroLevelUpDone(objectVisit.visitingHero);
} }
CDialogQuery::CDialogQuery(CGameHandler * owner):
CGhQuery(owner)
{
}
bool CDialogQuery::endsByPlayerAnswer() const bool CDialogQuery::endsByPlayerAnswer() const
{ {
return true; return true;
} }
bool CDialogQuery::blocksPack(const CPack *pack) const bool CDialogQuery::blocksPack(const CPack * pack) const
{ {
//We accept only query replies from correct player return blockAllButReply(pack);
if(auto reply = dynamic_ptr_cast<QueryReply>(pack))
{
return !vstd::contains(players, reply->player);
}
return true;
} }
CHeroMovementQuery::CHeroMovementQuery(const TryMoveHero &Tmh, const CGHeroInstance *Hero, bool VisitDestAfterVictory) void CDialogQuery::setReply(const JsonNode & reply)
: tmh(Tmh), visitDestAfterVictory(VisitDestAfterVictory), hero(Hero) {
if(reply.getType() == JsonNode::DATA_INTEGER)
answer = reply.Integer();
}
CHeroMovementQuery::CHeroMovementQuery(CGameHandler * owner, const TryMoveHero & Tmh, const CGHeroInstance * Hero, bool VisitDestAfterVictory):
CGhQuery(owner), tmh(Tmh), visitDestAfterVictory(VisitDestAfterVictory), hero(Hero)
{ {
players.push_back(hero->tempOwner); players.push_back(hero->tempOwner);
} }
void CHeroMovementQuery::onExposure(CGameHandler *gh, QueryPtr topQuery) void CHeroMovementQuery::onExposure(QueryPtr topQuery)
{ {
assert(players.size() == 1); assert(players.size() == 1);
@ -407,10 +440,10 @@ void CHeroMovementQuery::onExposure(CGameHandler *gh, QueryPtr topQuery)
gh->visitObjectOnTile(*gh->getTile(CGHeroInstance::convertPosition(tmh.end, false)), hero); gh->visitObjectOnTile(*gh->getTile(CGHeroInstance::convertPosition(tmh.end, false)), hero);
} }
gh->queries.popIfTop(*this); owner->popIfTop(*this);
} }
void CHeroMovementQuery::onRemoval(CGameHandler *gh, PlayerColor color) void CHeroMovementQuery::onRemoval(PlayerColor color)
{ {
PlayerBlocked pb; PlayerBlocked pb;
pb.player = color; pb.player = color;
@ -419,7 +452,7 @@ void CHeroMovementQuery::onRemoval(CGameHandler *gh, PlayerColor color)
gh->sendAndApply(&pb); gh->sendAndApply(&pb);
} }
void CHeroMovementQuery::onAdding(CGameHandler *gh, PlayerColor color) void CHeroMovementQuery::onAdding(PlayerColor color)
{ {
PlayerBlocked pb; PlayerBlocked pb;
pb.player = color; pb.player = color;
@ -427,3 +460,29 @@ void CHeroMovementQuery::onAdding(CGameHandler *gh, PlayerColor color)
pb.startOrEnd = PlayerBlocked::BLOCKADE_STARTED; pb.startOrEnd = PlayerBlocked::BLOCKADE_STARTED;
gh->sendAndApply(&pb); gh->sendAndApply(&pb);
} }
CGenericQuery::CGenericQuery(Queries * Owner, PlayerColor color, std::function<void(const JsonNode &)> Callback):
CQuery(Owner), callback(Callback)
{
addPlayer(color);
}
bool CGenericQuery::blocksPack(const CPack * pack) const
{
return blockAllButReply(pack);
}
bool CGenericQuery::endsByPlayerAnswer() const
{
return true;
}
void CGenericQuery::onExposure(QueryPtr topQuery)
{
//do nothing
}
void CGenericQuery::setReply(const JsonNode & reply)
{
callback(reply);
}

View File

@ -9,6 +9,9 @@ class CArmedInstance;
class CGameHandler; class CGameHandler;
class CObjectVisitQuery; class CObjectVisitQuery;
class CQuery; class CQuery;
class Queries;
class CSpell;
class SpellCastEnvironment;
typedef std::shared_ptr<CQuery> QueryPtr; typedef std::shared_ptr<CQuery> QueryPtr;
@ -22,40 +25,47 @@ typedef std::shared_ptr<CQuery> QueryPtr;
// Queries can cause another queries, forming a stack of queries for each player. Eg: hero movement -> object visit -> dialog. // Queries can cause another queries, forming a stack of queries for each player. Eg: hero movement -> object visit -> dialog.
class CQuery class CQuery
{ {
protected:
void addPlayer(PlayerColor color);
public: public:
std::vector<PlayerColor> players; //players that are affected (often "blocked") by query std::vector<PlayerColor> players; //players that are affected (often "blocked") by query
QueryID queryID; QueryID queryID;
CQuery(void); CQuery(Queries * Owner);
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 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 bool endsByPlayerAnswer() const; //query is removed after player gives answer (like dialogs)
virtual void onAdding(CGameHandler *gh, PlayerColor color); //called just before query is pushed on stack virtual void onAdding(PlayerColor color); //called just before query is pushed on stack
virtual void onRemoval(CGameHandler *gh, PlayerColor color); //called after query is removed from stack virtual void onAdded(PlayerColor color); //called right after query is pushed on stack
virtual void onExposure(CGameHandler *gh, QueryPtr topQuery);//called when query immediately above is removed and this is exposed (becomes top) virtual void onRemoval(PlayerColor color); //called after query is removed from stack
virtual void onExposure(QueryPtr topQuery);//called when query immediately above is removed and this is exposed (becomes top)
virtual std::string toString() const; virtual std::string toString() const;
virtual void notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const; virtual void notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const;
virtual void setReply(const JsonNode & reply);
virtual ~CQuery(void); virtual ~CQuery(void);
protected:
Queries * owner;
template <typename Handler> void serialize(Handler &h, const int version) void addPlayer(PlayerColor color);
{ bool blockAllButReply(const CPack * pack) const;
h & players & queryID;
}
}; };
std::ostream &operator<<(std::ostream &out, const CQuery &query); std::ostream &operator<<(std::ostream &out, const CQuery &query);
std::ostream &operator<<(std::ostream &out, QueryPtr query); std::ostream &operator<<(std::ostream &out, QueryPtr query);
class CGhQuery : public CQuery
{
public:
CGhQuery(CGameHandler * owner);
protected:
CGameHandler * gh;
};
//Created when hero visits object. //Created when hero visits object.
//Removed when query above is resolved (or immediately after visit if no queries were created) //Removed when query above is resolved (or immediately after visit if no queries were created)
class CObjectVisitQuery : public CQuery class CObjectVisitQuery : public CGhQuery
{ {
public: public:
const CGObjectInstance *visitedObject; const CGObjectInstance *visitedObject;
@ -63,14 +73,14 @@ public:
int3 tile; //may be different than hero pos -> eg. visit via teleport int3 tile; //may be different than hero pos -> eg. visit via teleport
bool removeObjectAfterVisit; bool removeObjectAfterVisit;
CObjectVisitQuery(const CGObjectInstance *Obj, const CGHeroInstance *Hero, int3 Tile); CObjectVisitQuery(CGameHandler * owner, const CGObjectInstance *Obj, const CGHeroInstance *Hero, int3 Tile);
virtual bool blocksPack(const CPack *pack) const override; virtual bool blocksPack(const CPack *pack) const override;
virtual void onRemoval(CGameHandler *gh, PlayerColor color) override; virtual void onRemoval(PlayerColor color) override;
virtual void onExposure(CGameHandler *gh, QueryPtr topQuery) override; virtual void onExposure(QueryPtr topQuery) override;
}; };
class CBattleQuery : public CQuery class CBattleQuery : public CGhQuery
{ {
public: public:
std::array<const CArmedInstance *,2> belligerents; std::array<const CArmedInstance *,2> belligerents;
@ -78,35 +88,38 @@ public:
const BattleInfo *bi; const BattleInfo *bi;
boost::optional<BattleResult> result; boost::optional<BattleResult> result;
CBattleQuery(); CBattleQuery(CGameHandler * owner);
CBattleQuery(const BattleInfo *Bi); //TODO CBattleQuery(CGameHandler * owner, const BattleInfo * Bi); //TODO
virtual void notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const override; virtual void notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const override;
virtual bool blocksPack(const CPack *pack) const override; virtual bool blocksPack(const CPack *pack) const override;
virtual void onRemoval(CGameHandler *gh, PlayerColor color) override; virtual void onRemoval(PlayerColor color) override;
}; };
//Created when hero attempts move and something happens //Created when hero attempts move and something happens
//(not necessarily position change, could be just an object interaction). //(not necessarily position change, could be just an object interaction).
class CHeroMovementQuery : public CQuery class CHeroMovementQuery : public CGhQuery
{ {
public: public:
TryMoveHero tmh; TryMoveHero tmh;
bool visitDestAfterVictory; //if hero moved to guarded tile and it should be visited once guard is defeated bool visitDestAfterVictory; //if hero moved to guarded tile and it should be visited once guard is defeated
const CGHeroInstance *hero; const CGHeroInstance *hero;
virtual void onExposure(CGameHandler *gh, QueryPtr topQuery) override; virtual void onExposure(QueryPtr topQuery) override;
CHeroMovementQuery(const TryMoveHero &Tmh, const CGHeroInstance *Hero, bool VisitDestAfterVictory = false); CHeroMovementQuery(CGameHandler * owner, const TryMoveHero & Tmh, const CGHeroInstance * Hero, bool VisitDestAfterVictory = false);
virtual void onAdding(CGameHandler *gh, PlayerColor color) override; virtual void onAdding(PlayerColor color) override;
virtual void onRemoval(CGameHandler *gh, PlayerColor color) override; virtual void onRemoval(PlayerColor color) override;
}; };
class CDialogQuery : public CQuery class CDialogQuery : public CGhQuery
{ {
public: public:
boost::optional<ui32> answer; CDialogQuery(CGameHandler * owner);
virtual bool endsByPlayerAnswer() const override; virtual bool endsByPlayerAnswer() const override;
virtual bool blocksPack(const CPack *pack) const override; virtual bool blocksPack(const CPack *pack) const override;
void setReply(const JsonNode & reply) override;
protected:
boost::optional<ui32> answer;
}; };
class CGarrisonDialogQuery : public CDialogQuery //used also for hero exchange dialogs class CGarrisonDialogQuery : public CDialogQuery //used also for hero exchange dialogs
@ -114,7 +127,7 @@ class CGarrisonDialogQuery : public CDialogQuery //used also for hero exchange d
public: public:
std::array<const CArmedInstance *,2> exchangingArmies; std::array<const CArmedInstance *,2> exchangingArmies;
CGarrisonDialogQuery(const CArmedInstance *up, const CArmedInstance *down); CGarrisonDialogQuery(CGameHandler * owner, const CArmedInstance *up, const CArmedInstance *down);
virtual void notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const override; virtual void notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const override;
virtual bool blocksPack(const CPack *pack) const override; virtual bool blocksPack(const CPack *pack) const override;
}; };
@ -125,7 +138,7 @@ class CBlockingDialogQuery : public CDialogQuery
public: public:
BlockingDialog bd; //copy of pack... debug purposes BlockingDialog bd; //copy of pack... debug purposes
CBlockingDialogQuery(const BlockingDialog &bd); CBlockingDialogQuery(CGameHandler * owner, const BlockingDialog &bd);
virtual void notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const override; virtual void notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const override;
}; };
@ -135,7 +148,7 @@ class CTeleportDialogQuery : public CDialogQuery
public: public:
TeleportDialog td; //copy of pack... debug purposes TeleportDialog td; //copy of pack... debug purposes
CTeleportDialogQuery(const TeleportDialog &td); CTeleportDialogQuery(CGameHandler * owner, const TeleportDialog &td);
virtual void notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const override; virtual void notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const override;
}; };
@ -143,27 +156,39 @@ public:
class CHeroLevelUpDialogQuery : public CDialogQuery class CHeroLevelUpDialogQuery : public CDialogQuery
{ {
public: public:
CHeroLevelUpDialogQuery(const HeroLevelUp &Hlu); CHeroLevelUpDialogQuery(CGameHandler * owner, const HeroLevelUp &Hlu);
virtual void onRemoval(CGameHandler *gh, PlayerColor color) override; virtual void onRemoval(PlayerColor color) override;
virtual void notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const override; virtual void notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const override;
HeroLevelUp hlu; HeroLevelUp hlu;
}; };
class CCommanderLevelUpDialogQuery : public CDialogQuery class CCommanderLevelUpDialogQuery : public CDialogQuery
{ {
public: public:
CCommanderLevelUpDialogQuery(const CommanderLevelUp &Clu); CCommanderLevelUpDialogQuery(CGameHandler * owner, const CommanderLevelUp &Clu);
virtual void onRemoval(CGameHandler *gh, PlayerColor color) override; virtual void onRemoval(PlayerColor color) override;
virtual void notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const override; virtual void notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const override;
CommanderLevelUp clu; CommanderLevelUp clu;
}; };
struct Queries class CGenericQuery : public CQuery
{
public:
CGenericQuery(Queries * Owner, PlayerColor color, std::function<void(const JsonNode &)> Callback);
bool blocksPack(const CPack * pack) const override;
bool endsByPlayerAnswer() const override;
void onExposure(QueryPtr topQuery) override;
void setReply(const JsonNode & reply) override;
private:
std::function<void(const JsonNode &)> callback;
};
class Queries
{ {
private: private:
void addQuery(PlayerColor player, QueryPtr query); void addQuery(PlayerColor player, QueryPtr query);
@ -172,7 +197,6 @@ private:
std::map<PlayerColor, std::vector<QueryPtr>> queries; //player => stack of queries std::map<PlayerColor, std::vector<QueryPtr>> queries; //player => stack of queries
public: public:
CGameHandler *gh;
static boost::mutex mx; static boost::mutex mx;
void addQuery(QueryPtr query); void addQuery(QueryPtr query);

View File

@ -9,6 +9,8 @@
#include "../lib/battle/BattleInfo.h" #include "../lib/battle/BattleInfo.h"
#include "../lib/battle/BattleAction.h" #include "../lib/battle/BattleAction.h"
#include "../lib/serializer/Connection.h" #include "../lib/serializer/Connection.h"
#include "../lib/spells/CSpellHandler.h"
#include "../lib/spells/ISpellMechanics.h"
#define PLAYER_OWNS(id) (gh->getPlayerAt(c)==gh->getOwner(id)) #define PLAYER_OWNS(id) (gh->getPlayerAt(c)==gh->getOwner(id))
@ -235,7 +237,7 @@ bool QueryReply::applyGh( CGameHandler *gh )
COMPLAIN_AND_RETURN("Cannot answer the query with id -1!"); COMPLAIN_AND_RETURN("Cannot answer the query with id -1!");
assert(vstd::contains(gh->states.players, player)); assert(vstd::contains(gh->states.players, player));
return gh->queryReply(qid, answer, player); return gh->queryReply(qid, reply, player);
} }
bool MakeAction::applyGh( CGameHandler *gh ) bool MakeAction::applyGh( CGameHandler *gh )
@ -275,10 +277,22 @@ bool DigWithHero::applyGh( CGameHandler *gh )
return gh->dig(gh->getHero(id)); return gh->dig(gh->getHero(id));
} }
bool CastAdvSpell::applyGh( CGameHandler *gh ) bool CastAdvSpell::applyGh(CGameHandler * gh)
{ {
ERROR_IF_NOT_OWNS(hid); ERROR_IF_NOT_OWNS(hid);
return gh->castSpell(gh->getHero(hid), sid, pos);
const CSpell * s = sid.toSpell();
if(!s)
ERROR_AND_RETURN;
const CGHeroInstance * h = gh->getHero(hid);
if(!h)
ERROR_AND_RETURN;
AdventureSpellCastParameters p;
p.caster = h;
p.pos = pos;
return s->adventureCast(gh->spellEnv, p);
} }
bool PlayerMessage::applyGh( CGameHandler *gh ) bool PlayerMessage::applyGh( CGameHandler *gh )