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

Implemented support for "coast visitable" objects:

- objects marked as coast visitable can be visited from land even when
placed in water
- added isBlockedVisitable and isCoastVisitable method to
CGObjectInstance
- implemented json config for these properties in banks
This commit is contained in:
Ivan Savenko 2023-06-21 16:49:44 +03:00
parent a84ccb37c2
commit f7b27da00e
20 changed files with 69 additions and 17 deletions

View File

@ -266,7 +266,7 @@ bool isBlockVisitObj(const int3 & pos)
{ {
if(auto obj = cb->getTopObj(pos)) if(auto obj = cb->getTopObj(pos))
{ {
if(obj->blockVisit) //we can't stand on that object if(obj->isBlockedVisitable()) //we can't stand on that object
return true; return true;
} }

View File

@ -216,7 +216,7 @@ bool isBlockVisitObj(const int3 & pos)
{ {
if(auto obj = cb->getTopObj(pos)) if(auto obj = cb->getTopObj(pos))
{ {
if(obj->blockVisit) //we can't stand on that object if(obj->isBlockedVisitable()) //we can't stand on that object
return true; return true;
} }

View File

@ -155,7 +155,7 @@ namespace Goals
// picking up resources does not yield any exploration at all. // picking up resources does not yield any exploration at all.
// if it blocks the way to some explorable tile AIPathfinder will take care of it // if it blocks the way to some explorable tile AIPathfinder will take care of it
if(obj && obj->blockVisit) if(obj && obj->isBlockedVisitable())
{ {
continue; continue;
} }

View File

@ -640,6 +640,8 @@
"shipwreck" : { "shipwreck" : {
"index" : 0, "index" : 0,
"resetDuration" : 0, "resetDuration" : 0,
"blockedVisitable" : true,
"coastVisitable" : true,
"name" : "Shipwreck", "name" : "Shipwreck",
"aiValue" : 2000, "aiValue" : 2000,
"rmg" : { "rmg" : {
@ -732,6 +734,7 @@
"derelictShip" : { "derelictShip" : {
"index" : 0, "index" : 0,
"resetDuration" : 0, "resetDuration" : 0,
"blockedVisitable" : true,
"name" : "Derelict Ship", "name" : "Derelict Ship",
"aiValue" : 4000, "aiValue" : 4000,
"rmg" : { "rmg" : {

View File

@ -1900,7 +1900,7 @@ std::vector<CGObjectInstance*> CGameState::guardingCreatures (int3 pos) const
{ {
for (CGObjectInstance* obj : posTile.visitableObjects) for (CGObjectInstance* obj : posTile.visitableObjects)
{ {
if(obj->blockVisit) if(obj->isBlockedVisitable())
{ {
if (obj->ID == Obj::MONSTER) // Monster if (obj->ID == Obj::MONSTER) // Monster
guards.push_back(obj); guards.push_back(obj);

View File

@ -30,6 +30,8 @@ void CBankInstanceConstructor::initTypeData(const JsonNode & input)
levels = input["levels"].Vector(); levels = input["levels"].Vector();
bankResetDuration = static_cast<si32>(input["resetDuration"].Float()); bankResetDuration = static_cast<si32>(input["resetDuration"].Float());
blockVisit = input["blockedVisitable"].Bool();
coastVisitable = input["coastVisitable"].Bool();
} }
BankConfig CBankInstanceConstructor::generateConfig(const JsonNode & level, CRandomGenerator & rng) const BankConfig CBankInstanceConstructor::generateConfig(const JsonNode & level, CRandomGenerator & rng) const
@ -58,6 +60,8 @@ BankConfig CBankInstanceConstructor::generateConfig(const JsonNode & level, CRan
void CBankInstanceConstructor::randomizeObject(CBank * bank, CRandomGenerator & rng) const void CBankInstanceConstructor::randomizeObject(CBank * bank, CRandomGenerator & rng) const
{ {
bank->resetDuration = bankResetDuration; bank->resetDuration = bankResetDuration;
bank->blockVisit = blockVisit;
bank->coastVisitable = coastVisitable;
si32 totalChance = 0; si32 totalChance = 0;
for(const auto & node : levels) for(const auto & node : levels)

View File

@ -80,12 +80,18 @@ class CBankInstanceConstructor : public CDefaultObjectTypeHandler<CBank>
BankConfig generateConfig(const JsonNode & conf, CRandomGenerator & rng) const; BankConfig generateConfig(const JsonNode & conf, CRandomGenerator & rng) const;
JsonVector levels; JsonVector levels;
// all banks of this type will be reset N days after clearing,
si32 bankResetDuration = 0;
// bank is only visitable from adjacent tile
bool blockVisit;
// bank is visitable from land even when bank is on water tile
bool coastVisitable;
protected: protected:
void initTypeData(const JsonNode & input) override; void initTypeData(const JsonNode & input) override;
public: public:
// all banks of this type will be reset N days after clearing,
si32 bankResetDuration = 0;
void randomizeObject(CBank * object, CRandomGenerator & rng) const override; void randomizeObject(CBank * object, CRandomGenerator & rng) const override;
@ -97,6 +103,8 @@ public:
{ {
h & levels; h & levels;
h & bankResetDuration; h & bankResetDuration;
h & blockVisit;
h & coastVisitable;
h & static_cast<CDefaultObjectTypeHandler<CBank>&>(*this); h & static_cast<CDefaultObjectTypeHandler<CBank>&>(*this);
} }
}; };

View File

@ -43,6 +43,11 @@ void CBank::initObj(CRandomGenerator & rand)
VLC->objtypeh->getHandlerFor(ID, subID)->configureObject(this, rand); VLC->objtypeh->getHandlerFor(ID, subID)->configureObject(this, rand);
} }
bool CBank::isCoastVisitable() const
{
return coastVisitable;
}
std::string CBank::getHoverText(PlayerColor player) const std::string CBank::getHoverText(PlayerColor player) const
{ {
// TODO: record visited players // TODO: record visited players

View File

@ -21,6 +21,7 @@ class DLL_LINKAGE CBank : public CArmedInstance
std::unique_ptr<BankConfig> bc; std::unique_ptr<BankConfig> bc;
ui32 daycounter; ui32 daycounter;
ui32 resetDuration; ui32 resetDuration;
bool coastVisitable;
void setPropertyDer(ui8 what, ui32 val) override; void setPropertyDer(ui8 what, ui32 val) override;
void doVisit(const CGHeroInstance * hero) const; void doVisit(const CGHeroInstance * hero) const;
@ -35,6 +36,7 @@ public:
std::string getHoverText(PlayerColor player) const override; std::string getHoverText(PlayerColor player) const override;
void newTurn(CRandomGenerator & rand) const override; void newTurn(CRandomGenerator & rand) const override;
bool wasVisited (PlayerColor player) const override; bool wasVisited (PlayerColor player) const override;
bool isCoastVisitable() const override;
void onHeroVisit(const CGHeroInstance * h) const override; void onHeroVisit(const CGHeroInstance * h) const override;
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override; void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override; void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
@ -45,6 +47,7 @@ public:
h & daycounter; h & daycounter;
h & bc; h & bc;
h & resetDuration; h & resetDuration;
h & coastVisitable;
} }
friend class CBankInstanceConstructor; friend class CBankInstanceConstructor;

View File

@ -122,6 +122,11 @@ TerrainId CGHeroInstance::getNativeTerrain() const
return nativeTerrain; return nativeTerrain;
} }
bool CGHeroInstance::isCoastVisitable() const
{
return true;
}
BattleField CGHeroInstance::getBattlefield() const BattleField CGHeroInstance::getBattlefield() const
{ {
return BattleField::NONE; return BattleField::NONE;

View File

@ -286,6 +286,7 @@ public:
void updateFrom(const JsonNode & data) override; void updateFrom(const JsonNode & data) override;
bool isCoastVisitable() const override;
BattleField getBattlefield() const override; BattleField getBattlefield() const override;
protected: protected:
void setPropertyDer(ui8 what, ui32 val) override;//synchr void setPropertyDer(ui8 what, ui32 val) override;//synchr

View File

@ -282,6 +282,16 @@ bool CGObjectInstance::isVisitable() const
return appearance->isVisitable(); return appearance->isVisitable();
} }
bool CGObjectInstance::isBlockedVisitable() const
{
return blockVisit;
}
bool CGObjectInstance::isCoastVisitable() const
{
return false;
}
bool CGObjectInstance::passableFor(PlayerColor color) const bool CGObjectInstance::passableFor(PlayerColor color) const
{ {
return false; return false;

View File

@ -34,8 +34,6 @@ public:
ObjectInstanceID id; ObjectInstanceID id;
/// Defines appearance of object on map (animation, blocked tiles, blit order, etc) /// Defines appearance of object on map (animation, blocked tiles, blit order, etc)
std::shared_ptr<const ObjectTemplate> appearance; std::shared_ptr<const ObjectTemplate> appearance;
/// If true hero can visit this object only from neighbouring tiles and can't stand on this object
bool blockVisit;
std::string instanceName; std::string instanceName;
std::string typeName; std::string typeName;
@ -49,6 +47,8 @@ public:
/// "center" tile from which the sight distance is calculated /// "center" tile from which the sight distance is calculated
int3 getSightCenter() const; int3 getSightCenter() const;
/// If true hero can visit this object only from neighbouring tiles and can't stand on this object
bool blockVisit;
PlayerColor getOwner() const override PlayerColor getOwner() const override
{ {
@ -68,7 +68,15 @@ public:
bool coveringAt(int x, int y) const; //returns true if object covers with picture location (x, y) (h3m pos) bool coveringAt(int x, int y) const; //returns true if object covers with picture location (x, y) (h3m pos)
std::set<int3> getBlockedPos() const; //returns set of positions blocked by this object std::set<int3> getBlockedPos() const; //returns set of positions blocked by this object
std::set<int3> getBlockedOffsets() const; //returns set of relative positions blocked by this object std::set<int3> getBlockedOffsets() const; //returns set of relative positions blocked by this object
bool isVisitable() const; //returns true if object is visitable
/// returns true if object is visitable
bool isVisitable() const;
/// If true hero can visit this object only from neighbouring tiles and can't stand on this object
virtual bool isBlockedVisitable() const;
/// If true this object can be visited by hero standing on the coast
virtual bool isCoastVisitable() const;
virtual BattleField getBattlefield() const; virtual BattleField getBattlefield() const;

View File

@ -246,7 +246,6 @@ public:
{ {
h & static_cast<IQuestObject&>(*this); h & static_cast<IQuestObject&>(*this);
h & static_cast<CGObjectInstance&>(*this); h & static_cast<CGObjectInstance&>(*this);
h & blockVisit;
} }
}; };

View File

@ -1294,6 +1294,11 @@ CGBoat::CGBoat()
layer = EPathfindingLayer::EEPathfindingLayer::SAIL; layer = EPathfindingLayer::EEPathfindingLayer::SAIL;
} }
bool CGBoat::isCoastVisitable() const
{
return true;
}
void CGSirens::initObj(CRandomGenerator & rand) void CGSirens::initObj(CRandomGenerator & rand)
{ {
blockVisit = true; blockVisit = true;

View File

@ -359,6 +359,7 @@ public:
std::array<std::string, PlayerColor::PLAYER_LIMIT_I> flagAnimations; std::array<std::string, PlayerColor::PLAYER_LIMIT_I> flagAnimations;
CGBoat(); CGBoat();
bool isCoastVisitable() const override;
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {

View File

@ -313,7 +313,7 @@ int3 CMap::guardingCreaturePosition (int3 pos) const
{ {
for (CGObjectInstance* obj : posTile.visitableObjects) for (CGObjectInstance* obj : posTile.visitableObjects)
{ {
if(obj->blockVisit) if(obj->isBlockedVisitable())
{ {
if (obj->ID == Obj::MONSTER) // Monster if (obj->ID == Obj::MONSTER) // Monster
return pos; return pos;

View File

@ -42,7 +42,7 @@ namespace PathfinderUtil
{ {
for(const CGObjectInstance * obj : tinfo.visitableObjects) for(const CGObjectInstance * obj : tinfo.visitableObjects)
{ {
if(obj->blockVisit) if(obj->isBlockedVisitable())
return EPathAccessibility::BLOCKVIS; return EPathAccessibility::BLOCKVIS;
else if(obj->passableFor(player)) else if(obj->passableFor(player))
return EPathAccessibility::ACCESSIBLE; return EPathAccessibility::ACCESSIBLE;

View File

@ -157,7 +157,7 @@ void DestinationActionRule::process(
} }
else if(destination.isGuardianTile) else if(destination.isGuardianTile)
action = EPathNodeAction::BATTLE; action = EPathNodeAction::BATTLE;
else if(destination.nodeObject->blockVisit && !(pathfinderConfig->options.useCastleGate && destination.nodeObject->ID == Obj::TOWN)) else if(destination.nodeObject->isBlockedVisitable() && !(pathfinderConfig->options.useCastleGate && destination.nodeObject->ID == Obj::TOWN))
action = EPathNodeAction::BLOCKING_VISIT; action = EPathNodeAction::BLOCKING_VISIT;
if(action == EPathNodeAction::NORMAL) if(action == EPathNodeAction::NORMAL)
@ -301,7 +301,7 @@ PathfinderBlockingRule::BlockingReason MovementToDestinationRule::getBlockingRea
if(!destination.isNodeObjectVisitable()) if(!destination.isNodeObjectVisitable())
return BlockingReason::DESTINATION_BLOCKED; return BlockingReason::DESTINATION_BLOCKED;
if(destination.nodeObject->ID != Obj::BOAT && !destination.nodeHero) if(!destination.nodeHero && !destination.nodeObject->isCoastVisitable())
return BlockingReason::DESTINATION_BLOCKED; return BlockingReason::DESTINATION_BLOCKED;
} }
else if(destination.isNodeObjectVisitable() && destination.nodeObject->ID == Obj::BOAT) else if(destination.isNodeObjectVisitable() && destination.nodeObject->ID == Obj::BOAT)

View File

@ -2294,7 +2294,7 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, boo
//OR hero is on land and dest is water and (there is not present only one object - boat) //OR hero is on land and dest is water and (there is not present only one object - boat)
if (((!t.terType->isPassable() || (t.blocked && !t.visitable && !canFly)) if (((!t.terType->isPassable() || (t.blocked && !t.visitable && !canFly))
&& complain("Cannot move hero, destination tile is blocked!")) && complain("Cannot move hero, destination tile is blocked!"))
|| ((!h->boat && !canWalkOnSea && !canFly && t.terType->isWater() && (t.visitableObjects.size() < 1 || (t.visitableObjects.back()->ID != Obj::BOAT && t.visitableObjects.back()->ID != Obj::HERO))) //hero is not on boat/water walking and dst water tile doesn't contain boat/hero (objs visitable from land) -> we test back cause boat may be on top of another object (#276) || ((!h->boat && !canWalkOnSea && !canFly && t.terType->isWater() && (t.visitableObjects.size() < 1 || !t.visitableObjects.back()->isCoastVisitable())) //hero is not on boat/water walking and dst water tile doesn't contain boat/hero (objs visitable from land) -> we test back cause boat may be on top of another object (#276)
&& complain("Cannot move hero, destination tile is on water!")) && complain("Cannot move hero, destination tile is on water!"))
|| ((h->boat && h->boat->layer == EPathfindingLayer::SAIL && t.terType->isLand() && t.blocked) || ((h->boat && h->boat->layer == EPathfindingLayer::SAIL && t.terType->isLand() && t.blocked)
&& complain("Cannot disembark hero, tile is blocked!")) && complain("Cannot disembark hero, tile is blocked!"))
@ -2369,10 +2369,10 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, boo
{ {
for (CGObjectInstance *obj : t.visitableObjects) for (CGObjectInstance *obj : t.visitableObjects)
{ {
if(h->boat && !obj->blockVisit && !h->boat->onboardVisitAllowed) if(h->boat && !obj->isBlockedVisitable() && !h->boat->onboardVisitAllowed)
return doMove(TryMoveHero::SUCCESS, this->IGNORE_GUARDS, DONT_VISIT_DEST, REMAINING_ON_TILE); return doMove(TryMoveHero::SUCCESS, this->IGNORE_GUARDS, DONT_VISIT_DEST, REMAINING_ON_TILE);
if (obj != h && obj->blockVisit && !obj->passableFor(h->tempOwner)) if (obj != h && obj->isBlockedVisitable() && !obj->passableFor(h->tempOwner))
{ {
EVisitDest visitDest = VISIT_DEST; EVisitDest visitDest = VISIT_DEST;
if(h->boat && !h->boat->onboardVisitAllowed) if(h->boat && !h->boat->onboardVisitAllowed)