mirror of
https://github.com/vcmi/vcmi.git
synced 2024-11-24 08:32:34 +02:00
Merge pull request #4609 from IvanSavenko/building_fixes
Building fixes
This commit is contained in:
commit
d0ac6458b9
@ -54,6 +54,7 @@
|
||||
#include "../../lib/entities/building/CBuilding.h"
|
||||
#include "../../lib/mapObjects/CGHeroInstance.h"
|
||||
#include "../../lib/mapObjects/CGTownInstance.h"
|
||||
#include "../../lib/mapObjects/TownBuildingInstance.h"
|
||||
|
||||
|
||||
static bool useCompactCreatureBox()
|
||||
@ -845,7 +846,21 @@ bool CCastleBuildings::buildingTryActivateCustomUI(BuildingID buildingToTest, Bu
|
||||
|
||||
void CCastleBuildings::enterRewardable(BuildingID building)
|
||||
{
|
||||
LOCPLINT->cb->visitTownBuilding(town, building);
|
||||
if (town->visitingHero == nullptr)
|
||||
{
|
||||
MetaString message;
|
||||
message.appendTextID("core.genrltxt.273"); // only visiting heroes may visit %s
|
||||
message.replaceTextID(town->town->buildings.at(building)->getNameTextID());
|
||||
|
||||
LOCPLINT->showInfoDialog(message.toString());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (town->rewardableBuildings.at(building)->wasVisited(town->visitingHero))
|
||||
enterBuilding(building);
|
||||
else
|
||||
LOCPLINT->cb->visitTownBuilding(town, building);
|
||||
}
|
||||
}
|
||||
|
||||
void CCastleBuildings::enterBlacksmith(BuildingID building, ArtifactID artifactID)
|
||||
|
@ -197,6 +197,7 @@ These are just a couple of examples of what can be done in VCMI. See vcmi config
|
||||
"bonuses" : [ BONUS_FORMAT ]
|
||||
|
||||
// If set to true, this building will not automatically activate on new day or on entering town and needs to be activated manually on click
|
||||
// Note that such building can only be activated by visiting hero, and not by garrisoned hero.
|
||||
"manualHeroVisit" : false,
|
||||
|
||||
// Bonuses provided by this special building if this building or any of its upgrades are constructed in town
|
||||
|
@ -246,6 +246,9 @@ void CRewardableObject::blockingDialogAnswered(const CGHeroInstance * hero, int3
|
||||
}
|
||||
else
|
||||
{
|
||||
if (answer == 0)
|
||||
return; //Player refused
|
||||
|
||||
if(answer > 0 && answer - 1 < configuration.info.size())
|
||||
{
|
||||
auto list = getAvailableRewards(hero, Rewardable::EEventType::EVENT_FIRST_VISIT);
|
||||
|
@ -165,6 +165,11 @@ void TownRewardableBuildingInstance::grantReward(ui32 rewardID, const CGHeroInst
|
||||
}
|
||||
}
|
||||
|
||||
bool TownRewardableBuildingInstance::wasVisited(const CGHeroInstance * contextHero) const
|
||||
{
|
||||
return wasVisitedBefore(contextHero);
|
||||
}
|
||||
|
||||
bool TownRewardableBuildingInstance::wasVisitedBefore(const CGHeroInstance * contextHero) const
|
||||
{
|
||||
switch (configuration.visitMode)
|
||||
|
@ -70,6 +70,7 @@ class DLL_LINKAGE TownRewardableBuildingInstance : public TownBuildingInstance,
|
||||
public:
|
||||
void setProperty(ObjProperty what, ObjPropertyID identifier) override;
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
bool wasVisited(const CGHeroInstance * contextHero) const override;
|
||||
|
||||
void newTurn(vstd::RNG & rand) const override;
|
||||
|
||||
|
@ -1171,7 +1171,6 @@ void CGameHandler::heroVisitCastle(const CGTownInstance * obj, const CGHeroInsta
|
||||
sendAndApply(&vc);
|
||||
}
|
||||
visitCastleObjects(obj, hero);
|
||||
giveSpells (obj, hero);
|
||||
|
||||
if (obj->visitingHero && obj->garrisonHero)
|
||||
useScholarSkill(obj->visitingHero->id, obj->garrisonHero->id);
|
||||
@ -1180,10 +1179,27 @@ void CGameHandler::heroVisitCastle(const CGTownInstance * obj, const CGHeroInsta
|
||||
|
||||
void CGameHandler::visitCastleObjects(const CGTownInstance * t, const CGHeroInstance * h)
|
||||
{
|
||||
std::vector<const CGHeroInstance * > visitors;
|
||||
visitors.push_back(h);
|
||||
visitCastleObjects(t, visitors);
|
||||
}
|
||||
|
||||
void CGameHandler::visitCastleObjects(const CGTownInstance * t, std::vector<const CGHeroInstance * > visitors)
|
||||
{
|
||||
std::vector<BuildingID> buildingsToVisit;
|
||||
for (auto const & hero : visitors)
|
||||
giveSpells (t, hero);
|
||||
|
||||
for (auto & building : t->rewardableBuildings)
|
||||
{
|
||||
if (!t->town->buildings.at(building.first)->manualHeroVisit)
|
||||
building.second->onHeroVisit(h);
|
||||
buildingsToVisit.push_back(building.first);
|
||||
}
|
||||
|
||||
if (!buildingsToVisit.empty())
|
||||
{
|
||||
auto visitQuery = std::make_shared<TownBuildingVisitQuery>(this, t, visitors, buildingsToVisit);
|
||||
queries->addQuery(visitQuery);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2144,10 +2160,15 @@ bool CGameHandler::buildStructure(ObjectInstanceID tid, BuildingID requestedID,
|
||||
|
||||
if (!force)
|
||||
{
|
||||
if(t->garrisonHero) //garrison hero first - consistent with original H3 Mana Vortex and Battle Scholar Academy levelup windows order
|
||||
objectVisited(t, t->garrisonHero);
|
||||
if(t->visitingHero)
|
||||
objectVisited(t, t->visitingHero);
|
||||
//garrison hero first - consistent with original H3 Mana Vortex and Battle Scholar Academy levelup windows order
|
||||
std::vector<const CGHeroInstance *> visitors;
|
||||
if (t->garrisonHero)
|
||||
visitors.push_back(t->garrisonHero);
|
||||
if (t->visitingHero)
|
||||
visitors.push_back(t->visitingHero);
|
||||
|
||||
if (!visitors.empty())
|
||||
visitCastleObjects(t, visitors);
|
||||
}
|
||||
|
||||
checkVictoryLossConditionsForPlayer(t->tempOwner);
|
||||
@ -2173,19 +2194,15 @@ bool CGameHandler::visitTownBuilding(ObjectInstanceID tid, BuildingID bid)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t->rewardableBuildings.count(bid))
|
||||
if (t->rewardableBuildings.count(bid) && t->visitingHero && t->town->buildings.at(bid)->manualHeroVisit)
|
||||
{
|
||||
auto & hero = t->garrisonHero ? t->garrisonHero : t->visitingHero;
|
||||
auto * building = t->rewardableBuildings.at(bid);
|
||||
|
||||
if (hero && t->town->buildings.at(bid)->manualHeroVisit)
|
||||
{
|
||||
auto visitQuery = std::make_shared<TownBuildingVisitQuery>(this, t, hero, bid);
|
||||
queries->addQuery(visitQuery);
|
||||
building->onHeroVisit(hero);
|
||||
queries->popIfTop(visitQuery);
|
||||
return true;
|
||||
}
|
||||
std::vector<BuildingID> buildingsToVisit;
|
||||
std::vector<const CGHeroInstance*> visitors;
|
||||
buildingsToVisit.push_back(bid);
|
||||
visitors.push_back(t->visitingHero);
|
||||
auto visitQuery = std::make_shared<TownBuildingVisitQuery>(this, t, visitors, buildingsToVisit);
|
||||
queries->addQuery(visitQuery);
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -182,6 +182,7 @@ public:
|
||||
void visitObjectOnTile(const TerrainTile &t, const CGHeroInstance * h);
|
||||
bool teleportHero(ObjectInstanceID hid, ObjectInstanceID dstid, ui8 source, PlayerColor asker = PlayerColor::NEUTRAL);
|
||||
void visitCastleObjects(const CGTownInstance * obj, const CGHeroInstance * hero) override;
|
||||
void visitCastleObjects(const CGTownInstance * obj, std::vector<const CGHeroInstance * > visitors);
|
||||
void levelUpHero(const CGHeroInstance * hero, SecondarySkill skill);//handle client respond and send one more request if needed
|
||||
void levelUpHero(const CGHeroInstance * hero);//initial call - check if hero have remaining levelups & handle them
|
||||
void levelUpCommander (const CCommanderInstance * c, int skill); //secondary skill 1 to 6, special skill : skill - 100
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include "VisitQueries.h"
|
||||
|
||||
#include "../../lib/mapObjects/CGHeroInstance.h"
|
||||
#include "../../lib/mapObjects/CGTownInstance.h"
|
||||
#include "../../lib/mapObjects/TownBuildingInstance.h"
|
||||
#include "../CGameHandler.h"
|
||||
#include "QueriesProcessor.h"
|
||||
|
||||
@ -29,7 +31,7 @@ bool VisitQuery::blocksPack(const CPack * pack) const
|
||||
return true;
|
||||
}
|
||||
|
||||
void VisitQuery::onExposure(QueryPtr topQuery)
|
||||
void MapObjectVisitQuery::onExposure(QueryPtr topQuery)
|
||||
{
|
||||
//Object may have been removed and deleted.
|
||||
if(gh->isValidObject(visitedObject))
|
||||
@ -54,13 +56,31 @@ void MapObjectVisitQuery::onRemoval(PlayerColor color)
|
||||
gh->removeObject(visitedObject, color);
|
||||
}
|
||||
|
||||
TownBuildingVisitQuery::TownBuildingVisitQuery(CGameHandler * owner, const CGObjectInstance * Obj, const CGHeroInstance * Hero, BuildingID buildingToVisit)
|
||||
: VisitQuery(owner, Obj, Hero)
|
||||
, visitedBuilding(buildingToVisit)
|
||||
TownBuildingVisitQuery::TownBuildingVisitQuery(CGameHandler * owner, const CGTownInstance * Obj, std::vector<const CGHeroInstance *> heroes, std::vector<BuildingID> buildingToVisit)
|
||||
: VisitQuery(owner, Obj, heroes.front())
|
||||
, visitedTown(Obj)
|
||||
{
|
||||
// generate in reverse order - first building-hero pair to handle must be in the end of vector
|
||||
for (auto const * hero : boost::adaptors::reverse(heroes))
|
||||
for (auto const & building : boost::adaptors::reverse(buildingToVisit))
|
||||
visitedBuilding.push_back({ hero, building});
|
||||
}
|
||||
|
||||
void TownBuildingVisitQuery::onRemoval(PlayerColor color)
|
||||
void TownBuildingVisitQuery::onExposure(QueryPtr topQuery)
|
||||
{
|
||||
|
||||
onAdded(players.front());
|
||||
}
|
||||
|
||||
void TownBuildingVisitQuery::onAdded(PlayerColor color)
|
||||
{
|
||||
while (!visitedBuilding.empty() && owner->topQuery(color).get() == this)
|
||||
{
|
||||
visitingHero = visitedBuilding.back().hero;
|
||||
auto * building = visitedTown->rewardableBuildings.at(visitedBuilding.back().building);
|
||||
building->onHeroVisit(visitingHero);
|
||||
visitedBuilding.pop_back();
|
||||
}
|
||||
|
||||
if (visitedBuilding.empty() && owner->topQuery(color).get() == this)
|
||||
owner->popIfTop(*this);
|
||||
}
|
||||
|
@ -11,19 +11,22 @@
|
||||
|
||||
#include "CQuery.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
class CGTownInstance;
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
//Created when hero visits object.
|
||||
//Removed when query above is resolved (or immediately after visit if no queries were created)
|
||||
class VisitQuery : public CQuery
|
||||
{
|
||||
protected:
|
||||
VisitQuery(CGameHandler * owner, const CGObjectInstance *Obj, const CGHeroInstance *Hero);
|
||||
VisitQuery(CGameHandler * owner, const CGObjectInstance * Obj, const CGHeroInstance * Hero);
|
||||
|
||||
public:
|
||||
const CGObjectInstance *visitedObject;
|
||||
const CGHeroInstance *visitingHero;
|
||||
const CGObjectInstance * visitedObject;
|
||||
const CGHeroInstance * visitingHero;
|
||||
|
||||
bool blocksPack(const CPack *pack) const final;
|
||||
void onExposure(QueryPtr topQuery) final;
|
||||
bool blocksPack(const CPack * pack) const final;
|
||||
};
|
||||
|
||||
class MapObjectVisitQuery final : public VisitQuery
|
||||
@ -31,17 +34,26 @@ class MapObjectVisitQuery final : public VisitQuery
|
||||
public:
|
||||
bool removeObjectAfterVisit;
|
||||
|
||||
MapObjectVisitQuery(CGameHandler * owner, const CGObjectInstance *Obj, const CGHeroInstance *Hero);
|
||||
MapObjectVisitQuery(CGameHandler * owner, const CGObjectInstance * Obj, const CGHeroInstance * Hero);
|
||||
|
||||
void onRemoval(PlayerColor color) final;
|
||||
void onExposure(QueryPtr topQuery) final;
|
||||
};
|
||||
|
||||
class TownBuildingVisitQuery final : public VisitQuery
|
||||
{
|
||||
struct BuildingVisit
|
||||
{
|
||||
const CGHeroInstance * hero;
|
||||
BuildingID building;
|
||||
};
|
||||
|
||||
const CGTownInstance * visitedTown;
|
||||
std::vector<BuildingVisit> visitedBuilding;
|
||||
|
||||
public:
|
||||
BuildingID visitedBuilding;
|
||||
TownBuildingVisitQuery(CGameHandler * owner, const CGTownInstance * Obj, std::vector<const CGHeroInstance *> heroes, std::vector<BuildingID> buildingToVisit);
|
||||
|
||||
TownBuildingVisitQuery(CGameHandler * owner, const CGObjectInstance *Obj, const CGHeroInstance *Hero, BuildingID buildingToVisit);
|
||||
|
||||
void onRemoval(PlayerColor color) final;
|
||||
void onAdded(PlayerColor color) final;
|
||||
void onExposure(QueryPtr topQuery) final;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user