Browse Source

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
Ivan Savenko 2 years ago
parent
commit
f7b27da00e

+ 1 - 1
AI/Nullkiller/AIUtility.cpp

@@ -266,7 +266,7 @@ bool isBlockVisitObj(const int3 & 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;
 	}
 

+ 1 - 1
AI/VCAI/AIUtility.cpp

@@ -216,7 +216,7 @@ bool isBlockVisitObj(const int3 & 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;
 	}
 

+ 1 - 1
AI/VCAI/Goals/Explore.cpp

@@ -155,7 +155,7 @@ namespace Goals
 
 					// 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(obj && obj->blockVisit)
+					if(obj && obj->isBlockedVisitable())
 					{
 						continue;
 					}

+ 3 - 0
config/objects/creatureBanks.json

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

+ 1 - 1
lib/CGameState.cpp

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

+ 4 - 0
lib/mapObjectConstructors/CBankInstanceConstructor.cpp

@@ -30,6 +30,8 @@ void CBankInstanceConstructor::initTypeData(const JsonNode & input)
 
 	levels = input["levels"].Vector();
 	bankResetDuration = static_cast<si32>(input["resetDuration"].Float());
+	blockVisit = input["blockedVisitable"].Bool();
+	coastVisitable = input["coastVisitable"].Bool();
 }
 
 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
 {
 	bank->resetDuration = bankResetDuration;
+	bank->blockVisit = blockVisit;
+	bank->coastVisitable = coastVisitable;
 
 	si32 totalChance = 0;
 	for(const auto & node : levels)

+ 10 - 2
lib/mapObjectConstructors/CBankInstanceConstructor.h

@@ -80,12 +80,18 @@ class CBankInstanceConstructor : public CDefaultObjectTypeHandler<CBank>
 	BankConfig generateConfig(const JsonNode & conf, CRandomGenerator & rng) const;
 
 	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:
 	void initTypeData(const JsonNode & input) override;
 
 public:
-	// all banks of this type will be reset N days after clearing,
-	si32 bankResetDuration = 0;
 
 	void randomizeObject(CBank * object, CRandomGenerator & rng) const override;
 
@@ -97,6 +103,8 @@ public:
 	{
 		h & levels;
 		h & bankResetDuration;
+		h & blockVisit;
+		h & coastVisitable;
 		h & static_cast<CDefaultObjectTypeHandler<CBank>&>(*this);
 	}
 };

+ 5 - 0
lib/mapObjects/CBank.cpp

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

+ 3 - 0
lib/mapObjects/CBank.h

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

+ 5 - 0
lib/mapObjects/CGHeroInstance.cpp

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

+ 1 - 0
lib/mapObjects/CGHeroInstance.h

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

+ 10 - 0
lib/mapObjects/CGObjectInstance.cpp

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

+ 11 - 3
lib/mapObjects/CGObjectInstance.h

@@ -34,8 +34,6 @@ public:
 	ObjectInstanceID id;
 	/// Defines appearance of object on map (animation, blocked tiles, blit order, etc)
 	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 typeName;
@@ -49,6 +47,8 @@ public:
 
 	/// "center" tile from which the sight distance is calculated
 	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
 	{
@@ -68,7 +68,15 @@ public:
 	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> 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;
 

+ 0 - 1
lib/mapObjects/CQuest.h

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

+ 5 - 0
lib/mapObjects/MiscObjects.cpp

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

+ 1 - 0
lib/mapObjects/MiscObjects.h

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

+ 1 - 1
lib/mapping/CMap.cpp

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

+ 1 - 1
lib/pathfinder/PathfinderUtil.h

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

+ 2 - 2
lib/pathfinder/PathfindingRules.cpp

@@ -157,7 +157,7 @@ void DestinationActionRule::process(
 			}
 			else if(destination.isGuardianTile)
 				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;
 
 			if(action == EPathNodeAction::NORMAL)
@@ -301,7 +301,7 @@ PathfinderBlockingRule::BlockingReason MovementToDestinationRule::getBlockingRea
 			if(!destination.isNodeObjectVisitable())
 				return BlockingReason::DESTINATION_BLOCKED;
 
-			if(destination.nodeObject->ID != Obj::BOAT && !destination.nodeHero)
+			if(!destination.nodeHero && !destination.nodeObject->isCoastVisitable())
 				return BlockingReason::DESTINATION_BLOCKED;
 		}
 		else if(destination.isNodeObjectVisitable() && destination.nodeObject->ID == Obj::BOAT)

+ 3 - 3
server/CGameHandler.cpp

@@ -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)
 	if (((!t.terType->isPassable()  ||  (t.blocked && !t.visitable && !canFly))
 			&& 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!"))
 		|| ((h->boat && h->boat->layer == EPathfindingLayer::SAIL && t.terType->isLand() && t.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)
 		{
-			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);
 			
-			if (obj != h && obj->blockVisit && !obj->passableFor(h->tempOwner))
+			if (obj != h && obj->isBlockedVisitable() && !obj->passableFor(h->tempOwner))
 			{
 				EVisitDest visitDest = VISIT_DEST;
 				if(h->boat && !h->boat->onboardVisitAllowed)