diff --git a/AI/Nullkiller/Goals/BuildBoat.cpp b/AI/Nullkiller/Goals/BuildBoat.cpp index 23a031939..5ca46dc1c 100644 --- a/AI/Nullkiller/Goals/BuildBoat.cpp +++ b/AI/Nullkiller/Goals/BuildBoat.cpp @@ -23,7 +23,7 @@ using namespace Goals; bool BuildBoat::operator==(const BuildBoat & other) const { - return shipyard->o->id == other.shipyard->o->id; + return shipyard == other.shipyard; } // //TSubgoal BuildBoat::decomposeSingle() const @@ -54,7 +54,7 @@ void BuildBoat::accept(AIGateway * ai) throw cannotFulfillGoalException("Can not afford boat"); } - if(cb->getPlayerRelations(ai->playerID, shipyard->o->tempOwner) == PlayerRelations::ENEMIES) + if(cb->getPlayerRelations(ai->playerID, shipyard->getObject()->getOwner()) == PlayerRelations::ENEMIES) { throw cannotFulfillGoalException("Can not build boat in enemy shipyard"); } @@ -65,9 +65,8 @@ void BuildBoat::accept(AIGateway * ai) } logAi->trace( - "Building boat at shipyard %s located at %s, estimated boat position %s", - shipyard->o->getObjectName(), - shipyard->o->visitablePos().toString(), + "Building boat at shipyard located at %s, estimated boat position %s", + shipyard->getObject()->visitablePos().toString(), shipyard->bestLocation().toString()); cb->buildBoat(shipyard); diff --git a/AI/Nullkiller/Pathfinding/Actions/BoatActions.cpp b/AI/Nullkiller/Pathfinding/Actions/BoatActions.cpp index e80ee0e03..9fcf052ce 100644 --- a/AI/Nullkiller/Pathfinding/Actions/BoatActions.cpp +++ b/AI/Nullkiller/Pathfinding/Actions/BoatActions.cpp @@ -32,9 +32,9 @@ namespace AIPathfinding Goals::TSubgoal BuildBoatAction::decompose(const CGHeroInstance * hero) const { - if(cb->getPlayerRelations(ai->playerID, shipyard->o->tempOwner) == PlayerRelations::ENEMIES) + if(cb->getPlayerRelations(ai->playerID, shipyard->getObject()->getOwner()) == PlayerRelations::ENEMIES) { - return Goals::sptr(Goals::CaptureObject(shipyard->o)); + return Goals::sptr(Goals::CaptureObject(targetObject())); } return Goals::sptr(Goals::Invalid()); @@ -44,7 +44,7 @@ namespace AIPathfinding { auto hero = source->actor->hero; - if(cb->getPlayerRelations(hero->tempOwner, shipyard->o->tempOwner) == PlayerRelations::ENEMIES) + if(cb->getPlayerRelations(hero->tempOwner, shipyard->getObject()->getOwner()) == PlayerRelations::ENEMIES) { #if NKAI_TRACE_LEVEL > 1 logAi->trace("Can not build a boat. Shipyard is enemy."); @@ -70,7 +70,7 @@ namespace AIPathfinding const CGObjectInstance * BuildBoatAction::targetObject() const { - return shipyard->o; + return dynamic_cast(shipyard); } const ChainActor * BuildBoatAction::getActor(const ChainActor * sourceActor) const @@ -101,7 +101,7 @@ namespace AIPathfinding std::string BuildBoatAction::toString() const { - return "Build Boat at " + shipyard->o->getObjectName(); + return "Build Boat at " + shipyard->getObject()->visitablePos().toString(); } bool SummonBoatAction::canAct(const AIPathNode * source) const diff --git a/AI/VCAI/Goals/BuildBoat.cpp b/AI/VCAI/Goals/BuildBoat.cpp index f5828005f..4c4136b22 100644 --- a/AI/VCAI/Goals/BuildBoat.cpp +++ b/AI/VCAI/Goals/BuildBoat.cpp @@ -22,14 +22,14 @@ using namespace Goals; bool BuildBoat::operator==(const BuildBoat & other) const { - return shipyard->o->id == other.shipyard->o->id; + return shipyard == other.shipyard; } TSubgoal BuildBoat::whatToDoToAchieve() { - if(cb->getPlayerRelations(ai->playerID, shipyard->o->tempOwner) == PlayerRelations::ENEMIES) + if(cb->getPlayerRelations(ai->playerID, shipyard->getObject()->getOwner()) == PlayerRelations::ENEMIES) { - return fh->chooseSolution(ai->ah->howToVisitObj(shipyard->o)); + return fh->chooseSolution(ai->ah->howToVisitObj(dynamic_cast(shipyard))); } if(shipyard->shipyardStatus() != IShipyard::GOOD) @@ -53,7 +53,7 @@ void BuildBoat::accept(VCAI * ai) throw cannotFulfillGoalException("Can not afford boat"); } - if(cb->getPlayerRelations(ai->playerID, shipyard->o->tempOwner) == PlayerRelations::ENEMIES) + if(cb->getPlayerRelations(ai->playerID, shipyard->getObject()->getOwner()) == PlayerRelations::ENEMIES) { throw cannotFulfillGoalException("Can not build boat in enemy shipyard"); } @@ -64,9 +64,8 @@ void BuildBoat::accept(VCAI * ai) } logAi->trace( - "Building boat at shipyard %s located at %s, estimated boat position %s", - shipyard->o->getObjectName(), - shipyard->o->visitablePos().toString(), + "Building boat at shipyard located at %s, estimated boat position %s", + shipyard->getObject()->visitablePos().toString(), shipyard->bestLocation().toString()); cb->buildBoat(shipyard); @@ -81,5 +80,5 @@ std::string BuildBoat::name() const std::string BuildBoat::completeMessage() const { - return "Boat have been built at " + shipyard->o->visitablePos().toString(); + return "Boat have been built at " + shipyard->getObject()->visitablePos().toString(); } diff --git a/CCallback.cpp b/CCallback.cpp index 948ca259f..b9826e278 100644 --- a/CCallback.cpp +++ b/CCallback.cpp @@ -301,7 +301,7 @@ void CCallback::sendMessage(const std::string &mess, const CGObjectInstance * cu void CCallback::buildBoat( const IShipyard *obj ) { BuildBoat bb; - bb.objid = obj->o->id; + bb.objid = dynamic_cast(obj)->id; sendRequest(&bb); } diff --git a/client/NetPacksClient.cpp b/client/NetPacksClient.cpp index 5cf74ae57..1ad096c6e 100644 --- a/client/NetPacksClient.cpp +++ b/client/NetPacksClient.cpp @@ -906,7 +906,7 @@ void ApplyClientNetPackVisitor::visitOpenWindow(OpenWindow & pack) case EOpenWindowMode::SHIPYARD_WINDOW: { const IShipyard *sy = IShipyard::castFrom(cl.getObj(ObjectInstanceID(pack.id1))); - callInterfaceIfPresent(cl, sy->o->tempOwner, &IGameEventsReceiver::showShipyardDialog, sy); + callInterfaceIfPresent(cl, sy->getObject()->getOwner(), &IGameEventsReceiver::showShipyardDialog, sy); } break; case EOpenWindowMode::THIEVES_GUILD: diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index 981f5f257..cc7294479 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/lib/mapObjects/CGHeroInstance.cpp @@ -225,7 +225,6 @@ int CGHeroInstance::maxMovePointsCached(bool onLand, const TurnInfo * ti) const } CGHeroInstance::CGHeroInstance(): - IBoatGenerator(this), tacticFormationEnabled(false), inTownGarrison(false), moveDir(4), @@ -973,6 +972,11 @@ void CGHeroInstance::getOutOffsets(std::vector &offsets) const }; } +const IObjectInterface * CGHeroInstance::getObject() const +{ + return this; +} + int32_t CGHeroInstance::getSpellCost(const spells::Spell * sp) const { return sp->getCost(getSpellSchoolLevel(sp)); diff --git a/lib/mapObjects/CGHeroInstance.h b/lib/mapObjects/CGHeroInstance.h index d6d1c1cb4..08d6f1cea 100644 --- a/lib/mapObjects/CGHeroInstance.h +++ b/lib/mapObjects/CGHeroInstance.h @@ -133,6 +133,7 @@ public: BoatId getBoatType() const override; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral void getOutOffsets(std::vector &offsets) const override; //offsets to obj pos when we boat can be placed + const IObjectInterface * getObject() const override; ////////////////////////////////////////////////////////////////////////// diff --git a/lib/mapObjects/CGTownInstance.cpp b/lib/mapObjects/CGTownInstance.cpp index fa80df1d8..d680f64d3 100644 --- a/lib/mapObjects/CGTownInstance.cpp +++ b/lib/mapObjects/CGTownInstance.cpp @@ -224,8 +224,6 @@ bool CGTownInstance::hasCapitol() const } CGTownInstance::CGTownInstance(): - IShipyard(this), - IMarket(), town(nullptr), builded(0), destroyed(0), @@ -590,6 +588,19 @@ void CGTownInstance::getOutOffsets( std::vector &offsets ) const offsets = {int3(-1,2,0), int3(-3,2,0)}; } +CGTownInstance::EGeneratorState CGTownInstance::shipyardStatus() const +{ + if (!hasBuilt(BuildingID::SHIPYARD)) + return EGeneratorState::UNKNOWN; + + return IShipyard::shipyardStatus(); +} + +const IObjectInterface * CGTownInstance::getObject() const +{ + return this; +} + void CGTownInstance::mergeGarrisonOnSiege() const { auto getWeakestStackSlot = [&](ui64 powerLimit) diff --git a/lib/mapObjects/CGTownInstance.h b/lib/mapObjects/CGTownInstance.h index 05a78c90a..1e914df89 100644 --- a/lib/mapObjects/CGTownInstance.h +++ b/lib/mapObjects/CGTownInstance.h @@ -46,6 +46,8 @@ class DLL_LINKAGE CGTownInstance : public CGDwelling, public IShipyard, public I { std::string name; // name of town public: + using CGDwelling::getPosition; + enum EFortLevel {NONE = 0, FORT = 1, CITADEL = 2, CASTLE = 3}; CTownAndVisitingHero townAndVis; @@ -71,7 +73,6 @@ public: template void serialize(Handler &h, const int version) { h & static_cast(*this); - h & static_cast(*this); h & name; h & builded; h & destroyed; @@ -134,6 +135,8 @@ public: int getSightRadius() const override; //returns sight distance BoatId getBoatType() const override; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral void getOutOffsets(std::vector &offsets) const override; //offsets to obj pos when we boat can be placed. Parameter will be cleared + EGeneratorState shipyardStatus() const override; + const IObjectInterface * getObject() const override; int getMarketEfficiency() const override; //=market count bool allowsTrade(EMarketMode::EMarketMode mode) const override; std::vector availableItemsIds(EMarketMode::EMarketMode mode) const override; diff --git a/lib/mapObjects/IObjectInterface.cpp b/lib/mapObjects/IObjectInterface.cpp index 5be5edf33..512a52315 100644 --- a/lib/mapObjects/IObjectInterface.cpp +++ b/lib/mapObjects/IObjectInterface.cpp @@ -92,10 +92,10 @@ int3 IBoatGenerator::bestLocation() const for (auto & offset : offsets) { - if(const TerrainTile *tile = IObjectInterface::cb->getTile(o->pos + offset, false)) //tile is in the map + if(const TerrainTile *tile = getObject()->cb->getTile(getObject()->getPosition() + offset, false)) //tile is in the map { if(tile->terType->isWater() && (!tile->blocked || tile->blockingObjects.front()->ID == Obj::BOAT)) //and is water and is not blocked or is blocked by boat - return o->pos + offset; + return getObject()->getPosition() + offset; } } return int3 (-1,-1,-1); @@ -107,24 +107,14 @@ IBoatGenerator::EGeneratorState IBoatGenerator::shipyardStatus() const const TerrainTile *t = IObjectInterface::cb->getTile(tile); if(!t) return TILE_BLOCKED; //no available water - else if(t->blockingObjects.empty()) + + if(t->blockingObjects.empty()) return GOOD; //OK - else if(t->blockingObjects.front()->ID == Obj::BOAT) + + if(t->blockingObjects.front()->ID == Obj::BOAT) return BOAT_ALREADY_BUILT; //blocked with boat - else - return TILE_BLOCKED; //blocked -} -BoatId IBoatGenerator::getBoatType() const -{ - //We make good ships by default - return EBoatId::BOAT_GOOD; -} - - -IBoatGenerator::IBoatGenerator(const CGObjectInstance *O) -: o(O) -{ + return TILE_BLOCKED; //blocked } void IBoatGenerator::getProblemText(MetaString &out, const CGHeroInstance *visitor) const @@ -144,7 +134,7 @@ void IBoatGenerator::getProblemText(MetaString &out, const CGHeroInstance *visit out.addTxt(MetaString::ADVOB_TXT, 189); break; case NO_WATER: - logGlobal->error("Shipyard without water! %s \t %d", o->pos.toString(), o->id.getNum()); + logGlobal->error("Shipyard without water at tile %s! ", getObject()->getPosition().toString()); return; } } @@ -155,34 +145,9 @@ void IShipyard::getBoatCost(TResources & cost) const cost[EGameResID::GOLD] = 1000; } -IShipyard::IShipyard(const CGObjectInstance *O) - : IBoatGenerator(O) -{ -} - -IShipyard * IShipyard::castFrom( CGObjectInstance *obj ) -{ - if(!obj) - return nullptr; - - if(obj->ID == Obj::TOWN) - { - return dynamic_cast(obj); - } - else if(obj->ID == Obj::SHIPYARD) - { - return dynamic_cast(obj); - } - else - { - return nullptr; - } -} - const IShipyard * IShipyard::castFrom( const CGObjectInstance *obj ) { - return castFrom(const_cast(obj)); + return dynamic_cast(obj); } - VCMI_LIB_NAMESPACE_END diff --git a/lib/mapObjects/IObjectInterface.h b/lib/mapObjects/IObjectInterface.h index 700898051..d724bb7fc 100644 --- a/lib/mapObjects/IObjectInterface.h +++ b/lib/mapObjects/IObjectInterface.h @@ -78,39 +78,25 @@ public: class DLL_LINKAGE IBoatGenerator { public: - const CGObjectInstance *o; - - IBoatGenerator(const CGObjectInstance *O); virtual ~IBoatGenerator() = default; - virtual BoatId getBoatType() const; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral - virtual void getOutOffsets(std::vector &offsets) const =0; //offsets to obj pos when we boat can be placed + virtual const IObjectInterface * getObject() const = 0; + + virtual BoatId getBoatType() const = 0; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral + virtual void getOutOffsets(std::vector & offsets) const = 0; //offsets to obj pos when we boat can be placed int3 bestLocation() const; //returns location when the boat should be placed - enum EGeneratorState {GOOD, BOAT_ALREADY_BUILT, TILE_BLOCKED, NO_WATER}; - EGeneratorState shipyardStatus() const; //0 - can buid, 1 - there is already a boat at dest tile, 2 - dest tile is blocked, 3 - no water + enum EGeneratorState {GOOD, BOAT_ALREADY_BUILT, TILE_BLOCKED, NO_WATER, UNKNOWN}; + virtual EGeneratorState shipyardStatus() const; void getProblemText(MetaString &out, const CGHeroInstance *visitor = nullptr) const; - - template void serialize(Handler &h, const int version) - { - h & o; - } }; class DLL_LINKAGE IShipyard : public IBoatGenerator { public: - IShipyard(const CGObjectInstance *O); - virtual void getBoatCost(ResourceSet & cost) const; static const IShipyard *castFrom(const CGObjectInstance *obj); - static IShipyard *castFrom(CGObjectInstance *obj); - - template void serialize(Handler &h, const int version) - { - h & static_cast(*this); - } }; VCMI_LIB_NAMESPACE_END diff --git a/lib/mapObjects/MiscObjects.cpp b/lib/mapObjects/MiscObjects.cpp index af5e8edfa..b4d475de1 100644 --- a/lib/mapObjects/MiscObjects.cpp +++ b/lib/mapObjects/MiscObjects.cpp @@ -1915,12 +1915,6 @@ void CGSirens::onHeroVisit( const CGHeroInstance * h ) const } } cb->showInfoDialog(&iw); - -} - -CGShipyard::CGShipyard() - :IShipyard(this) -{ } void CGShipyard::getOutOffsets( std::vector &offsets ) const @@ -1935,6 +1929,11 @@ void CGShipyard::getOutOffsets( std::vector &offsets ) const }; } +const IObjectInterface * CGShipyard::getObject() const +{ + return this; +} + void CGShipyard::onHeroVisit( const CGHeroInstance * h ) const { if(!cb->gameState()->getPlayerRelations(tempOwner, h->tempOwner)) @@ -1960,6 +1959,11 @@ void CGShipyard::serializeJsonOptions(JsonSerializeFormat& handler) serializeJsonOwner(handler); } +BoatId CGShipyard::getBoatType() const +{ + return EBoatId::BOAT_GOOD; +} + void CCartographer::onHeroVisit( const CGHeroInstance * h ) const { //if player has not bought map of this subtype yet and underground exist for stalagmite cartographer diff --git a/lib/mapObjects/MiscObjects.h b/lib/mapObjects/MiscObjects.h index 8315a434a..1f8db5b72 100644 --- a/lib/mapObjects/MiscObjects.h +++ b/lib/mapObjects/MiscObjects.h @@ -461,14 +461,11 @@ class DLL_LINKAGE CGShipyard : public CGObjectInstance, public IShipyard { public: void getOutOffsets(std::vector &offsets) const override; //offsets to obj pos when we boat can be placed - CGShipyard(); void onHeroVisit(const CGHeroInstance * h) const override; + const IObjectInterface * getObject() const override; + BoatId getBoatType() const override; + - template void serialize(Handler &h, const int version) - { - h & static_cast(*this); - h & static_cast(*this); - } protected: void serializeJsonOptions(JsonSerializeFormat & handler) override; }; diff --git a/lib/registerTypes/RegisterTypes.h b/lib/registerTypes/RegisterTypes.h index a37a61d16..1a0e2c95d 100644 --- a/lib/registerTypes/RegisterTypes.h +++ b/lib/registerTypes/RegisterTypes.h @@ -62,7 +62,7 @@ void registerTypesMapObjects1(Serializer &s) s.template registerType(); s.template registerType(); s.template registerType(); - s.template registerType(); s.template registerType(); + s.template registerType(); s.template registerType(); s.template registerType(); s.template registerType(); @@ -75,9 +75,9 @@ void registerTypesMapObjects1(Serializer &s) s.template registerType(); s.template registerType(); s.template registerType(); // Armed objects - s.template registerType(); s.template registerType(); s.template registerType(); + s.template registerType(); s.template registerType(); s.template registerType(); - s.template registerType(); s.template registerType(); + s.template registerType(); s.template registerType(); s.template registerType(); s.template registerType(); diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index b55f2bc00..92761f37d 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -5627,12 +5627,6 @@ bool CGameHandler::buildBoat(ObjectInstanceID objid, PlayerColor playerID) complain("Cannot build boat in this shipyard!"); return false; } - else if (obj->o->ID == Obj::TOWN - && !static_cast(obj)->hasBuilt(BuildingID::SHIPYARD)) - { - complain("Cannot build boat in the town - no shipyard!"); - return false; - } TResources boatCost; obj->getBoatCost(boatCost);