From a8265c7052f6afa33ac68031fd50e7d183a3727e Mon Sep 17 00:00:00 2001 From: Nordsoft91 Date: Mon, 23 May 2022 13:08:36 +0300 Subject: [PATCH] [0002285] Implement feature with extra resources near mines (#742) * RMG: clear start position * [0002285] some heaps of resources are placed nearby mines * Fix leak in case of inability to place resource * Fix indentation according to vcmi style * Add constant for random amount of resources * Code review fixes --- lib/mapObjects/MiscObjects.cpp | 4 +- lib/mapObjects/MiscObjects.h | 2 + lib/rmg/CRmgTemplateZone.cpp | 105 ++++++++++++++++++++------------- lib/rmg/CRmgTemplateZone.h | 2 + 4 files changed, 71 insertions(+), 42 deletions(-) diff --git a/lib/mapObjects/MiscObjects.cpp b/lib/mapObjects/MiscObjects.cpp index 92ecc6118..9ec8d9c52 100644 --- a/lib/mapObjects/MiscObjects.cpp +++ b/lib/mapObjects/MiscObjects.cpp @@ -838,14 +838,14 @@ std::string CGResource::getHoverText(PlayerColor player) const CGResource::CGResource() { - amount = 0; + amount = CGResource::RANDOM_AMOUNT; } void CGResource::initObj(CRandomGenerator & rand) { blockVisit = true; - if(!amount) + if(amount == CGResource::RANDOM_AMOUNT) { switch(subID) { diff --git a/lib/mapObjects/MiscObjects.h b/lib/mapObjects/MiscObjects.h index 5a02b07f9..a6ad8567e 100644 --- a/lib/mapObjects/MiscObjects.h +++ b/lib/mapObjects/MiscObjects.h @@ -215,7 +215,9 @@ protected: class DLL_LINKAGE CGResource : public CArmedInstance { public: + static const ui32 RANDOM_AMOUNT = 0; ui32 amount; //0 if random + std::string message; CGResource(); diff --git a/lib/rmg/CRmgTemplateZone.cpp b/lib/rmg/CRmgTemplateZone.cpp index 69d657fe7..afb0dc791 100644 --- a/lib/rmg/CRmgTemplateZone.cpp +++ b/lib/rmg/CRmgTemplateZone.cpp @@ -790,6 +790,10 @@ void CRmgTemplateZone::addCloseObject(CGObjectInstance * obj, si32 strength) { closeObjects.push_back(std::make_pair(obj, strength)); } +void CRmgTemplateZone::addNearbyObject(CGObjectInstance * obj, CGObjectInstance * nearbyTarget) +{ + nearbyObjects.push_back(std::make_pair(obj, nearbyTarget)); +} void CRmgTemplateZone::addToConnectLater(const int3& src) { @@ -1106,14 +1110,17 @@ void CRmgTemplateZone::initTownType () //cut a ring around town to ensure crunchPath always hits it. auto cutPathAroundTown = [this](const CGTownInstance * town) { + auto clearPos = [this](const int3 & pos) + { + if (gen->isPossible(pos)) + gen->setOccupied(pos, ETileType::FREE); + }; for (auto blockedTile : town->getBlockedPos()) { - gen->foreach_neighbour(blockedTile, [this](const int3 & pos) - { - if (gen->isPossible(pos)) - gen->setOccupied(pos, ETileType::FREE); - }); + gen->foreach_neighbour(blockedTile, clearPos); } + //clear town entry + gen->foreach_neighbour(town->visitablePos()+int3{0,1,0}, clearPos); }; auto addNewTowns = [&totalTowns, this, &cutPathAroundTown](int count, bool hasFort, PlayerColor player) @@ -1294,53 +1301,39 @@ void CRmgTemplateZone::paintZoneTerrain (ETerrainType terrainType) bool CRmgTemplateZone::placeMines () { - static const Res::ERes woodOre[] = {Res::ERes::WOOD, Res::ERes::ORE}; - static const Res::ERes preciousResources[] = {Res::ERes::GEMS, Res::ERes::CRYSTAL, Res::ERes::MERCURY, Res::ERes::SULFUR}; - - std::array factory = + using namespace Res; + static const std::map mineValue{{ERes::WOOD, 1500}, {ERes::ORE, 1500}, {ERes::GEMS, 3500}, {ERes::CRYSTAL, 3500}, {ERes::MERCURY, 3500}, {ERes::SULFUR, 3500}, {ERes::GOLD, 7000}}; + + std::vector createdMines; + + for(const auto & mineInfo : mines) { - VLC->objtypeh->getHandlerFor(Obj::MINE, 0), - VLC->objtypeh->getHandlerFor(Obj::MINE, 1), - VLC->objtypeh->getHandlerFor(Obj::MINE, 2), - VLC->objtypeh->getHandlerFor(Obj::MINE, 3), - VLC->objtypeh->getHandlerFor(Obj::MINE, 4), - VLC->objtypeh->getHandlerFor(Obj::MINE, 5), - VLC->objtypeh->getHandlerFor(Obj::MINE, 6) - }; - - for (const auto & res : woodOre) - { - for (int i = 0; i < mines[res]; i++) + ERes res = (ERes)mineInfo.first; + for(int i = 0; i < mineInfo.second; ++i) { - auto mine = (CGMine *) factory.at(static_cast(res))->create(ObjectTemplate()); + auto mine = (CGMine*) VLC->objtypeh->getHandlerFor(Obj::MINE, res)->create(ObjectTemplate()); mine->producedResource = res; mine->tempOwner = PlayerColor::NEUTRAL; mine->producedQuantity = mine->defaultResProduction(); - if (!i) - addCloseObject(mine, 1500); //only firts one is close + createdMines.push_back(mine); + + if(!i && (res == ERes::WOOD || res == ERes::ORE)) + addCloseObject(mine, mineValue.at(res)); //only first woor&ore mines are close else - addRequiredObject(mine, 1500); + addRequiredObject(mine, mineValue.at(res)); } } - for (const auto & res : preciousResources) + + //create extra resources + for(auto * mine : createdMines) { - for (int i = 0; i < mines[res]; i++) + for(int rc = gen->rand.nextInt(1, 3); rc > 0; --rc) { - auto mine = (CGMine *) factory.at(static_cast(res))->create(ObjectTemplate()); - mine->producedResource = res; - mine->tempOwner = PlayerColor::NEUTRAL; - mine->producedQuantity = mine->defaultResProduction(); - addRequiredObject(mine, 3500); + auto resourse = (CGResource*) VLC->objtypeh->getHandlerFor(Obj::RESOURCE, mine->producedResource)->create(ObjectTemplate()); + resourse->amount = CGResource::RANDOM_AMOUNT; + addNearbyObject(resourse, mine); } } - for (int i = 0; i < mines[Res::GOLD]; i++) - { - auto mine = (CGMine *) factory.at(Res::GOLD)->create(ObjectTemplate()); - mine->producedResource = Res::GOLD; - mine->tempOwner = PlayerColor::NEUTRAL; - mine->producedQuantity = mine->defaultResProduction(); - addRequiredObject(mine, 7000); - } return true; } @@ -1463,6 +1456,38 @@ bool CRmgTemplateZone::createRequiredObjects() } } + //create nearby objects (e.g. extra resources close to mines) + for(const auto & object : nearbyObjects) + { + auto obj = object.first; + std::set possiblePositions; + for (auto blockedTile : object.second->getBlockedPos()) + { + gen->foreachDirectNeighbour(blockedTile, [this, &possiblePositions](int3 pos) + { + if (!gen->isBlocked(pos)) + { + //some resources still could be unaccessible, at least one free cell shall be + gen->foreach_neighbour(pos, [this, &possiblePositions, &pos](int3 p) + { + if(gen->isFree(p)) + possiblePositions.insert(pos); + }); + } + }); + } + + if(possiblePositions.empty()) + { + delete obj; //is it correct way to prevent leak? + } + else + { + auto pos = *RandomGeneratorUtil::nextItem(possiblePositions, gen->rand); + placeObject(obj, pos); + } + } + return true; } diff --git a/lib/rmg/CRmgTemplateZone.h b/lib/rmg/CRmgTemplateZone.h index 2656f4699..31018abe9 100644 --- a/lib/rmg/CRmgTemplateZone.h +++ b/lib/rmg/CRmgTemplateZone.h @@ -111,6 +111,7 @@ public: void addRequiredObject(CGObjectInstance * obj, si32 guardStrength=0); void addCloseObject(CGObjectInstance * obj, si32 guardStrength = 0); + void addNearbyObject(CGObjectInstance * obj, CGObjectInstance * nearbyTarget); void addToConnectLater(const int3& src); bool addMonster(int3 &pos, si32 strength, bool clearSurroundingTiles = true, bool zoneGuard = false); bool createTreasurePile(int3 &pos, float minDistance, const CTreasureInfo& treasureInfo); @@ -173,6 +174,7 @@ private: //content info std::vector> requiredObjects; std::vector> closeObjects; + std::vector> nearbyObjects; std::vector objects; //placement info