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

Treasure piles can now cover several tiles.

This commit is contained in:
DjWarmonger 2014-06-05 17:19:11 +02:00
parent c470b9606b
commit e54c816c92
5 changed files with 109 additions and 48 deletions

View File

@ -377,7 +377,7 @@ int3 whereToExplore(HeroPtr h)
}
}
}
removeDuplicates (nearbyVisitableObjs); //one object may occupy multiple tiles
vstd::removeDuplicates (nearbyVisitableObjs); //one object may occupy multiple tiles
boost::sort(nearbyVisitableObjs, isCloser);
if(nearbyVisitableObjs.size())
return nearbyVisitableObjs.back()->visitablePos();

View File

@ -135,44 +135,6 @@ bool objWithID(const CGObjectInstance *obj)
return obj->ID == id;
}
template <typename Container, typename Item>
bool erase_if_present(Container &c, const Item &item)
{
auto i = std::find(c.begin(), c.end(), item);
if (i != c.end())
{
c.erase(i);
return true;
}
return false;
}
template <typename V, typename Item, typename Item2>
bool erase_if_present(std::map<Item,V> & c, const Item2 &item)
{
auto i = c.find(item);
if (i != c.end())
{
c.erase(i);
return true;
}
return false;
}
template <typename Container, typename Pred>
void erase(Container &c, Pred pred)
{
c.erase(boost::remove_if(c, pred), c.end());
}
template<typename T>
void removeDuplicates(std::vector<T> &vec)
{
boost::sort(vec);
vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
}
std::string strFromInt3(int3 pos);
void foreach_tile_pos(std::function<void(const int3& pos)> foo);
void foreach_tile_pos(CCallback * cbp, std::function<void(CCallback * cbp, const int3& pos)> foo); // avoid costly retrieval of thread-specific pointer

View File

@ -608,6 +608,44 @@ namespace vstd
return defaultValue;
}
template <typename Container, typename Item>
bool erase_if_present(Container &c, const Item &item)
{
auto i = std::find(c.begin(), c.end(), item);
if (i != c.end())
{
c.erase(i);
return true;
}
return false;
}
template <typename V, typename Item, typename Item2>
bool erase_if_present(std::map<Item,V> & c, const Item2 &item)
{
auto i = c.find(item);
if (i != c.end())
{
c.erase(i);
return true;
}
return false;
}
template <typename Container, typename Pred>
void erase(Container &c, Pred pred)
{
c.erase(boost::remove_if(c, pred), c.end());
}
template<typename T>
void removeDuplicates(std::vector<T> &vec)
{
boost::sort(vec);
vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
}
using boost::math::round;
}
using vstd::operator-=;

View File

@ -124,6 +124,8 @@ DLL_LINKAGE void HeroVisitCastle::applyGs( CGameState *gs )
CGHeroInstance *h = gs->getHero(hid);
CGTownInstance *t = gs->getTown(tid);
assert(h);
assert(t);
if(start())
t->setVisitingHero(h);
else

View File

@ -460,7 +460,11 @@ bool CRmgTemplateZone::addMonster(CMapGenerator* gen, int3 &pos, si32 strength)
bool CRmgTemplateZone::createTreasurePile (CMapGenerator* gen, int3 &pos)
{
//TODO: read treasure values from template
std::map<int3, CGObjectInstance *> treasures;
std::set<int3> boundary;
int3 guardPos;
int3 nextTreasurePos = pos;
//default values
int maxValue = 5000;
@ -477,6 +481,28 @@ bool CRmgTemplateZone::createTreasurePile (CMapGenerator* gen, int3 &pos)
CGObjectInstance * object = nullptr;
while (currentValue < minValue)
{
//TODO: this works only for 1-tile objects
//make sure our shape is consistent
treasures[nextTreasurePos] = nullptr;
for (auto treasurePos : treasures)
{
gen->foreach_neighbour (treasurePos.first, [gen, &boundary](int3 pos)
{
boundary.insert(pos);
});
}
for (auto treasurePos : treasures)
{
//leaving only boundary around objects
vstd::erase_if_present (boundary, treasurePos.first);
}
for (auto tile : boundary)
{
//we can't extend boundary anymore
if (!(gen->isBlocked(tile) || gen->isPossible(tile)))
break;
}
int remaining = maxValue - currentValue;
auto oi = getRandomObject(gen, remaining);
@ -484,13 +510,47 @@ bool CRmgTemplateZone::createTreasurePile (CMapGenerator* gen, int3 &pos)
if (!object)
break;
//TODO: generate actual zone and not just all objects on a pile
currentValue += oi.value;
placeObject(gen, object, pos);
treasures[nextTreasurePos] = object;
//now find place for next object
int3 placeFound(-1,-1,-1);
for (auto tile : boundary)
{
if (gen->isPossible(tile)) //we can place new treasure only on possible tile
{
bool here = true;
gen->foreach_neighbour (tile, [gen, &here](int3 pos)
{
if (!(gen->isBlocked(pos) || gen->isPossible(pos)))
here = false;
});
if (here)
{
placeFound = tile;
break;
}
}
}
if (placeFound.valid())
nextTreasurePos = placeFound;
}
if (object)
if (treasures.size())
{
guardObject (gen, object, currentValue);
for (auto treasure : treasures)
{
placeObject(gen, treasure.second, treasure.first);
}
guardPos = *RandomGeneratorUtil::nextItem(boundary, gen->rand);
if (addMonster(gen, guardPos, currentValue))
{//block only if object is guarded
for (auto tile : boundary)
{
if (gen->isPossible(tile))
gen->setOccupied (tile, ETileType::BLOCKED);
}
}
return true;
}
else //we did not place eveyrthing successfully
@ -680,13 +740,12 @@ bool CRmgTemplateZone::fill(CMapGenerator* gen)
town->builtBuildings.insert(BuildingID::DEFAULT);
placeObject(gen, town, getPos() + town->getVisitableOffset()); //towns are big objects and should be centered around visitable position
logGlobal->traceStream() << "Placed object";
logGlobal->traceStream() << "Fill player info " << player_id;
auto & playerInfo = gen->map->players[player_id];
// Update player info
playerInfo.allowedFactions.clear();
playerInfo.allowedFactions.insert(town->subID);
playerInfo.allowedFactions.insert(townId);
playerInfo.hasMainTown = true;
playerInfo.posOfMainTown = town->pos - int3(2, 0, 0);
playerInfo.generateHeroAtMainTown = true;
@ -913,7 +972,7 @@ bool CRmgTemplateZone::guardObject(CMapGenerator* gen, CGObjectInstance* object,
}
auto guard_tile = *RandomGeneratorUtil::nextItem(tiles, gen->rand);
if (addMonster (gen, guard_tile, str)) //do not lace obstacles aroudn unguarded object
if (addMonster (gen, guard_tile, str)) //do not place obstacles around unguarded object
{
for (auto pos : tiles)
gen->setOccupied(pos, ETileType::BLOCKED);