1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Moved town portal logic to mechanics class

This commit is contained in:
AlexVinS 2017-07-03 21:09:27 +03:00
parent 3d1a84875e
commit a65befaa08
13 changed files with 212 additions and 199 deletions

View File

@ -1208,8 +1208,6 @@ void CPlayerInterface::showMapObjectSelectDialog(QueryID askID, const Component
cb->sendQueryReply(reply, askID);
};
CComponent * localIcon = new CComponent(icon);
const std::string localTitle = title.toString();
const std::string localDescription = description.toString();
@ -1219,7 +1217,7 @@ void CPlayerInterface::showMapObjectSelectDialog(QueryID askID, const Component
for(auto item : objects)
tempList.push_back(item.getNum());
CObjectListWindow * wnd = new CObjectListWindow(tempList, localIcon, localTitle, localDescription, selectCallback);
CObjectListWindow * wnd = new CObjectListWindow(tempList, icon, localTitle, localDescription, selectCallback);
wnd->onExit = cancelCallback;
GH.pushInt(wnd);
}

View File

@ -641,78 +641,12 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
delete owner;
});
if(mySpell->id == SpellID::TOWN_PORTAL)
{
//special case
//todo: move to mechanics
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
{
owner->myInt->cb->castSpell(h, mySpell->id, int3());// - town->getVisitableOffset());
}
else
{ //let the player choose
std::vector <int> availableTowns;
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->getTargetType() == CSpell::LOCATION)
{
adventureInt->enterCastingMode(mySpell);
}
else if(mySpell->getTargetType() == CSpell::NO_TARGET)
{
owner->myInt->cb->castSpell(h, mySpell->id);
}
else
{
logGlobal->error("Invalid spell target type");
}
}
}
}

View File

@ -1744,6 +1744,26 @@ CObjectListWindow::CObjectListWindow(const std::vector<int> &_items, CIntObject
init(titlePic, _title, _descr);
}
CObjectListWindow::CObjectListWindow(const std::vector<int> &_items, const Component & titlePic, std::string _title, std::string _descr,
std::function<void(int)> Callback):
CWindowObject(PLAYER_COLORED, "TPGATE"),
onSelect(Callback),
selected(0)
{
items.reserve(_items.size());
for(int id : _items)
{
items.push_back(std::make_pair(id, CGI->mh->map->objects[id]->getObjectName()));
}
OBJ_CONSTRUCTION_CAPTURING_ALL;
CComponent * icon = new CComponent(titlePic);
init(icon, _title, _descr);
}
CObjectListWindow::CObjectListWindow(const std::vector<std::string> &_items, CIntObject * titlePic, std::string _title, std::string _descr,
std::function<void(int)> Callback):
CWindowObject(PLAYER_COLORED, "TPGATE"),

View File

@ -33,6 +33,7 @@ class CToggleButton;
class CToggleGroup;
class CVolumeSlider;
class CGStatusBar;
struct Component;
/// Recruitment window where you can recruit creatures
class CRecruitmentWindow : public CWindowObject
@ -177,6 +178,10 @@ public:
///item names will be taken from map objects
CObjectListWindow(const std::vector<int> &_items, CIntObject * titlePic, std::string _title, std::string _descr,
std::function<void(int)> Callback);
CObjectListWindow(const std::vector<int> &_items, const Component & titlePic, std::string _title, std::string _descr,
std::function<void(int)> Callback);
CObjectListWindow(const std::vector<std::string> &_items, CIntObject * titlePic, std::string _title, std::string _descr,
std::function<void(int)> Callback);

View File

@ -25,7 +25,7 @@ AdventureSpellMechanics::AdventureSpellMechanics(const CSpell * s):
{
}
bool AdventureSpellMechanics::adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const
bool AdventureSpellMechanics::adventureCast(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
{
if(!owner->isAdventureSpell())
{
@ -55,29 +55,12 @@ bool AdventureSpellMechanics::adventureCast(const SpellCastEnvironment * env, Ad
return false;
}
{
AdvmapSpellCast asc;
asc.caster = caster;
asc.spellID = owner->id;
env->sendAndApply(&asc);
}
ESpellCastResult result = beginCast(env, parameters);
switch(applyAdventureEffects(env, parameters))
{
case ESpellCastResult::OK:
{
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;
if(result == ESpellCastResult::OK)
performCast(env, parameters);
return result != ESpellCastResult::ERROR;
}
ESpellCastResult AdventureSpellMechanics::applyAdventureEffects(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
@ -109,6 +92,42 @@ ESpellCastResult AdventureSpellMechanics::applyAdventureEffects(const SpellCastE
}
}
ESpellCastResult AdventureSpellMechanics::beginCast(const SpellCastEnvironment * env, const 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)
@ -308,7 +327,7 @@ TownPortalMechanics::TownPortalMechanics(const CSpell * s):
ESpellCastResult TownPortalMechanics::applyAdventureEffects(const SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
{
const CGTownInstance * destination = nullptr;
const int movementCost = GameConstants::BASE_MOVEMENT_COST * ((parameters.caster->getSpellSchoolLevel(owner) >= 3) ? 2 : 3);
const int moveCost = movementCost(parameters);
if(parameters.caster->getSpellSchoolLevel(owner) < 2)
{
@ -316,24 +335,12 @@ ESpellCastResult TownPortalMechanics::applyAdventureEffects(const SpellCastEnvir
destination = findNearestTown(env, parameters, pool);
if(nullptr == destination)
{
InfoWindow iw;
iw.player = parameters.caster->tempOwner;
iw.text.addTxt(MetaString::GENERAL_TXT, 124);
env->sendAndApply(&iw);
return ESpellCastResult::CANCEL;
}
return ESpellCastResult::ERROR;
if(parameters.caster->movement < movementCost)
{
InfoWindow iw;
iw.player = parameters.caster->tempOwner;
iw.text.addTxt(MetaString::GENERAL_TXT, 125);
env->sendAndApply(&iw);
return ESpellCastResult::CANCEL;
}
if(parameters.caster->movement < moveCost)
return ESpellCastResult::ERROR;
if (destination->visitingHero)
if(destination->visitingHero)
{
InfoWindow iw;
iw.player = parameters.caster->tempOwner;
@ -367,7 +374,7 @@ ESpellCastResult TownPortalMechanics::applyAdventureEffects(const SpellCastEnvir
return ESpellCastResult::ERROR;
}
if(parameters.caster->movement < movementCost)
if(parameters.caster->movement < moveCost)
{
env->complain("This hero has not enough movement points!");
return ESpellCastResult::ERROR;
@ -385,16 +392,99 @@ ESpellCastResult TownPortalMechanics::applyAdventureEffects(const SpellCastEnvir
return ESpellCastResult::ERROR;
}
if(env->moveHero(parameters.caster->id, destination->visitablePos() + parameters.caster->getVisitableOffset(), 1))
if(env->moveHero(parameters.caster->id, destination->visitablePos() + parameters.caster->getVisitableOffset(), true))
{
SetMovePoints smp;
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);
}
return ESpellCastResult::OK;
}
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())
@ -432,6 +522,11 @@ std::vector <const CGTownInstance*> TownPortalMechanics::getPossibleTowns(const
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)

View File

@ -18,6 +18,7 @@ enum class ESpellCastResult
{
OK,
CANCEL,//cast failed but it is not an error
PENDING,
ERROR//internal error occurred
};
@ -26,10 +27,13 @@ class DLL_LINKAGE AdventureSpellMechanics : public IAdventureSpellMechanics
public:
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:
///actual adventure cast implementation
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
@ -62,8 +66,10 @@ public:
TownPortalMechanics(const CSpell * s);
protected:
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;
};

View File

@ -118,7 +118,7 @@ void CSpell::applyBattle(BattleInfo * battle, const BattleSpellCast * packet) co
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);

View File

@ -306,7 +306,7 @@ public:
///Server logic. Has write access to GameState via packets.
///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;
public:

View File

@ -13,6 +13,8 @@
#include "CSpellHandler.h"
#include "../battle/BattleHex.h"
struct Query;
///callback to be provided by server
class DLL_LINKAGE SpellCastEnvironment
{
@ -26,7 +28,9 @@ public:
virtual const CMap * getMap() 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
@ -140,7 +144,7 @@ public:
IAdventureSpellMechanics(const CSpell * s);
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(const CSpell * s);
protected:

View File

@ -71,7 +71,8 @@ public:
void complain(const std::string & problem) const override;
const CMap * getMap() 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:
mutable CGameHandler * gh;
};
@ -6516,13 +6517,20 @@ const CGameInfoCallback * ServerSpellCastEnvironment::getCb() const
return gh;
}
const CMap * ServerSpellCastEnvironment::getMap() const
{
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

@ -3,7 +3,6 @@
#include "CGameHandler.h"
#include "../lib/battle/BattleInfo.h"
#include "../lib/mapObjects/MiscObjects.h"
#include "../lib/spells/ISpellMechanics.h"
boost::mutex Queries::mx;
@ -86,6 +85,7 @@ void CQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) cons
void CQuery::onExposure(QueryPtr topQuery)
{
logGlobal->trace("Exposed query with id %d", queryID);
owner->popQuery(*this);
}
@ -472,66 +472,29 @@ void CHeroMovementQuery::onAdding(PlayerColor color)
gh->sendAndApply(&pb);
}
CMapObjectSelectQuery::CMapObjectSelectQuery(Queries * Owner):
CQuery(Owner)
CGenericQuery::CGenericQuery(Queries * Owner, PlayerColor color, std::function<void(const JsonNode &)> Callback):
CQuery(Owner), callback(Callback)
{
addPlayer(color);
}
bool CMapObjectSelectQuery::blocksPack(const CPack * pack) const
bool CGenericQuery::blocksPack(const CPack * pack) const
{
return blockAllButReply(pack);
}
bool CMapObjectSelectQuery::endsByPlayerAnswer() const
bool CGenericQuery::endsByPlayerAnswer() const
{
return true;
}
void CMapObjectSelectQuery::setReply(const JsonNode & reply)
void CGenericQuery::onExposure(QueryPtr topQuery)
{
//TODO:
//do nothing
}
CSpellQuery::CSpellQuery(Queries * Owner, const SpellCastEnvironment * SpellEnv):
CQuery(Owner), spellEnv(SpellEnv)
void CGenericQuery::setReply(const JsonNode & reply)
{
}
AdventureSpellCastQuery::AdventureSpellCastQuery(Queries * Owner, const SpellCastEnvironment * SpellEnv, const CSpell * Spell, const CGHeroInstance * Caster, const int3 & Position):
CSpellQuery(Owner, SpellEnv), spell(Spell), caster(Caster), position(Position), requiresPositions(false)
{
assert(owner);
assert(spellEnv);
assert(spell);
assert(caster);
addPlayer(caster->getOwner());
}
bool AdventureSpellCastQuery::blocksPack(const CPack * pack) const
{
return true;
}
void AdventureSpellCastQuery::onAdded(PlayerColor color)
{
//TODO: destination select request
}
void AdventureSpellCastQuery::onExposure(QueryPtr topQuery)
{
CQuery::onExposure(topQuery);
}
void AdventureSpellCastQuery::onRemoval(PlayerColor color)
{
AdventureSpellCastParameters p;
p.caster = caster;
p.pos = position;
spell->adventureCast(spellEnv, p);
callback(reply);
}

View File

@ -175,39 +175,17 @@ public:
CommanderLevelUp clu;
};
class CMapObjectSelectQuery : public CQuery
class CGenericQuery : public CQuery
{
public:
CMapObjectSelectQuery(Queries * Owner);
CGenericQuery(Queries * Owner, PlayerColor color, std::function<void(const JsonNode &)> Callback);
bool blocksPack(const CPack * pack) const override;
bool endsByPlayerAnswer() const override;
void setReply(const JsonNode & reply) override;
};
class CSpellQuery : public CQuery
{
public:
CSpellQuery(Queries * Owner, const SpellCastEnvironment * SpellEnv);
protected:
const SpellCastEnvironment * spellEnv;
};
class AdventureSpellCastQuery : public CSpellQuery
{
public:
AdventureSpellCastQuery(Queries * Owner, const SpellCastEnvironment * SpellEnv, const CSpell * Spell, const CGHeroInstance * Caster, const int3 & Position);
bool blocksPack(const CPack * pack) const override;
void onAdded(PlayerColor color) override;
void onExposure(QueryPtr topQuery) override;
void onRemoval(PlayerColor color) override;
const CSpell * spell;
const CGHeroInstance * caster;
int3 position;
bool requiresPositions;
void setReply(const JsonNode & reply) override;
private:
std::function<void(const JsonNode &)> callback;
};
class Queries

View File

@ -9,6 +9,8 @@
#include "../lib/battle/BattleInfo.h"
#include "../lib/battle/BattleAction.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))
@ -286,11 +288,11 @@ bool CastAdvSpell::applyGh(CGameHandler * gh)
if(!h)
ERROR_AND_RETURN;
auto query = std::make_shared<AdventureSpellCastQuery>(&gh->queries, gh->spellEnv, s, h, pos);
AdventureSpellCastParameters p;
p.caster = h;
p.pos = pos;
gh->queries.addQuery(query);
gh->queries.popIfTop(query);//if we already can perform cast do it now
return true;
return s->adventureCast(gh->spellEnv, p);
}
bool PlayerMessage::applyGh( CGameHandler *gh )