From 219e897db03870a70c7008be2779c27bcdadebdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Zieli=C5=84ski?= Date: Sat, 20 May 2023 12:02:30 +0200 Subject: [PATCH] Added missing files. --- lib/mapping/ObstacleProxy.cpp | 216 ++++++++++++++++++++++++++++ lib/mapping/ObstacleProxy.h | 79 ++++++++++ lib/rmg/modificators/WaterProxy.cpp | 2 +- 3 files changed, 296 insertions(+), 1 deletion(-) create mode 100644 lib/mapping/ObstacleProxy.cpp create mode 100644 lib/mapping/ObstacleProxy.h diff --git a/lib/mapping/ObstacleProxy.cpp b/lib/mapping/ObstacleProxy.cpp new file mode 100644 index 000000000..29840954b --- /dev/null +++ b/lib/mapping/ObstacleProxy.cpp @@ -0,0 +1,216 @@ +/* + * ObstacleProxy.cpp, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ + +#pragma once + +#include "ObstacleProxy.h" +#include "../mapObjects/CObjectClassesHandler.h" +#include "../mapObjects/CObjectHandler.h" +#include "../mapping/CMap.h" + +VCMI_LIB_NAMESPACE_BEGIN + +void ObstacleProxy::collectPossibleObstacles(TerrainId terrain) +{ + //get all possible obstacles for this terrain + for(auto primaryID : VLC->objtypeh->knownObjects()) + { + for(auto secondaryID : VLC->objtypeh->knownSubObjects(primaryID)) + { + auto handler = VLC->objtypeh->getHandlerFor(primaryID, secondaryID); + if(handler->isStaticObject()) + { + for(const auto & temp : handler->getTemplates()) + { + if(temp->canBePlacedAt(terrain) && temp->getBlockMapOffset().valid()) + obstaclesBySize[temp->getBlockedOffsets().size()].push_back(temp); + } + } + } + } + for(const auto & o : obstaclesBySize) + { + possibleObstacles.emplace_back(o); + } + boost::sort(possibleObstacles, [](const ObstaclePair &p1, const ObstaclePair &p2) -> bool + { + return p1.first > p2.first; //bigger obstacles first + }); +} + +void ObstacleProxy::addBlockedTile(const int3& tile) +{ + blockedArea.add(tile); +} + +void ObstacleProxy::setBlockedArea(const rmg::Area& area) +{ + blockedArea = area; +} + +void ObstacleProxy::clearBlockedArea() +{ + blockedArea.clear(); +} + +bool ObstacleProxy::isProhibited(const rmg::Area& objArea) const +{ + return false; +}; + +int ObstacleProxy::getWeightedObjects(const int3 & tile, CRandomGenerator & rand, std::list & allObjects, std::vector> & weightedObjects) +{ + int maxWeight = std::numeric_limits::min(); + for(auto & possibleObstacle : possibleObstacles) + { + if(!possibleObstacle.first) + continue; + + auto shuffledObstacles = possibleObstacle.second; + RandomGeneratorUtil::randomShuffle(shuffledObstacles, rand); + + for(const auto & temp : shuffledObstacles) + { + auto handler = VLC->objtypeh->getHandlerFor(temp->id, temp->subid); + auto * obj = handler->create(temp); + allObjects.emplace_back(*obj); + rmg::Object * rmgObject = &allObjects.back(); + for(const auto & offset : obj->getBlockedOffsets()) + { + rmgObject->setPosition(tile - offset); + + if(!isInTheMap(rmgObject->getPosition())) + continue; + + if(!rmgObject->getArea().getSubarea([this](const int3 & t) + { + return !isInTheMap(t); + }).empty()) + continue; + + if(isProhibited(rmgObject->getArea())) + continue; + + int coverageBlocked = 0; + int coveragePossible = 0; + //do not use area intersection in optimization purposes + for(const auto & t : rmgObject->getArea().getTilesVector()) + { + auto coverage = verifyCoverage(t); + if(coverage.first) + ++coverageBlocked; + if(coverage.second) + ++coveragePossible; + } + + int coverageOverlap = possibleObstacle.first - coverageBlocked - coveragePossible; + int weight = possibleObstacle.first + coverageBlocked - coverageOverlap * possibleObstacle.first; + assert(coverageOverlap >= 0); + + if(weight > maxWeight) + { + weightedObjects.clear(); + maxWeight = weight; + weightedObjects.emplace_back(rmgObject, rmgObject->getPosition()); + if(weight > 0) + break; + } + else if(weight == maxWeight) + weightedObjects.emplace_back(rmgObject, rmgObject->getPosition()); + + } + } + + if(maxWeight > 0) + break; + } + + return maxWeight; +} + +std::set ObstacleProxy::createObstacles(CRandomGenerator & rand) +{ + //reverse order, since obstacles begin in bottom-right corner, while the map coordinates begin in top-left + auto blockedTiles = blockedArea.getTilesVector(); + int tilePos = 0; + std::set objs; + + while(!blockedArea.empty() && tilePos < blockedArea.getTilesVector().size()) + { + auto tile = blockedArea.getTilesVector()[tilePos]; + + std::list allObjects; + std::vector> weightedObjects; + int maxWeight = getWeightedObjects(tile, rand, allObjects, weightedObjects); + + if(weightedObjects.empty()) + { + tilePos += 1; + continue; + } + + auto objIter = RandomGeneratorUtil::nextItem(weightedObjects, rand); + objIter->first->setPosition(objIter->second); + placeObject(*objIter->first, objs); + + blockedArea.subtract(objIter->first->getArea()); + tilePos = 0; + + postProcess(*objIter->first); + + if(maxWeight < 0) + logGlobal->warn("Placed obstacle with negative weight at %s", objIter->second.toString()); + + for(auto & o : allObjects) + { + if(&o != objIter->first) + o.clear(); + } + } + + return objs; +} + +//FIXME: Only editor placer obstacles directly + +void ObstacleProxy::finalInsertion(CMapEditManager * manager, std::set & instances) +{ + manager->insertObjects(instances); //insert as one operation - for undo purposes +} + +std::pair ObstacleProxy::verifyCoverage(const int3 & t) const +{ + return {blockedArea.contains(t), false}; +} + +void ObstacleProxy::placeObject(rmg::Object & object, std::set & instances) +{ + for (auto * instance : object.instances()) + { + instances.insert(&instance->object()); + } +} + +EditorObstaclePlacer::EditorObstaclePlacer(CMap* map): + map(map) +{ +} + +bool EditorObstaclePlacer::isInTheMap(const int3& tile) +{ + return map->isInTheMap(tile); +} + +void EditorObstaclePlacer::placeObstacles(CRandomGenerator & rand) +{ + finalInsertion(map->getEditManager(), createObstacles(rand)); +} + +VCMI_LIB_NAMESPACE_END \ No newline at end of file diff --git a/lib/mapping/ObstacleProxy.h b/lib/mapping/ObstacleProxy.h new file mode 100644 index 000000000..b5607da86 --- /dev/null +++ b/lib/mapping/ObstacleProxy.h @@ -0,0 +1,79 @@ +/* + * ObstacleProxy.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ + +#pragma once + +#include "StdInc.h" +#include "../rmg/RmgObject.h" +#include "CMapEditManager.h" + +VCMI_LIB_NAMESPACE_BEGIN + +class CMapEditManager; +class CGObjectInstance; +class ObjectTemplate; +class CRandomGenerator; + +class DLL_LINKAGE ObstacleProxy +{ + //Base class generating random obstacles for RMG and map editor +public: + ObstacleProxy() = default; + virtual ~ObstacleProxy() = default; + + void collectPossibleObstacles(TerrainId terrain); + + void addBlockedTile(const int3 & tile); + + void setBlockedArea(const rmg::Area & area); + + void clearBlockedArea(); + + virtual bool isProhibited(const rmg::Area& objArea) const; + + virtual std::pair verifyCoverage(const int3 & t) const; + + virtual void placeObject(rmg::Object & object, std::set & instances); + + virtual std::set ObstacleProxy::createObstacles(CRandomGenerator & rand); + + virtual bool isInTheMap(const int3& tile) = 0; + + void finalInsertion(CMapEditManager * manager, std::set & instances); + + void placeObstacles( CRandomGenerator & rand); + + virtual void postProcess(const rmg::Object& object) {}; + +protected: + int getWeightedObjects(const int3& tile, CRandomGenerator& rand, std::list& allObjects, std::vector>& weightedObjects); + + rmg::Area blockedArea; + + using ObstacleVector = std::vector>; + std::map obstaclesBySize; + using ObstaclePair = std::pair; + std::vector possibleObstacles; +}; + +class DLL_LINKAGE EditorObstaclePlacer : public ObstacleProxy +{ +public: + EditorObstaclePlacer(CMap* map); + + bool isInTheMap(const int3& tile) override; + + void EditorObstaclePlacer::placeObstacles(CRandomGenerator& rand); + +private: + CMap* map; +}; + +VCMI_LIB_NAMESPACE_END \ No newline at end of file diff --git a/lib/rmg/modificators/WaterProxy.cpp b/lib/rmg/modificators/WaterProxy.cpp index 3e2fec725..4d95aaec4 100644 --- a/lib/rmg/modificators/WaterProxy.cpp +++ b/lib/rmg/modificators/WaterProxy.cpp @@ -231,7 +231,7 @@ bool WaterProxy::placeBoat(Zone & land, const Lake & lake, RouteInfo & info) if(sailingBoatTypes.empty()) return false; - auto * boat = dynamic_cast(VLC->objtypeh->getHandlerFor(Obj::BOAT, *RandomGeneratorUtil::nextItem(sailingBoatTypes, generator.rand))->create()); + auto * boat = dynamic_cast(VLC->objtypeh->getHandlerFor(Obj::BOAT, *RandomGeneratorUtil::nextItem(sailingBoatTypes, zone.getRand()))->create()); rmg::Object rmgObject(*boat); rmgObject.setTemplate(zone.getTerrainType());