|
|
@@ -620,6 +620,7 @@ bool CRmgTemplateZone::addMonster(CMapGenerator* gen, int3 &pos, si32 strength,
|
|
|
auto guard = new CGCreature();
|
|
|
guard->ID = Obj::MONSTER;
|
|
|
guard->subID = creId;
|
|
|
+ guard->character = 1; //MUST be initialized or switch will diverge
|
|
|
auto hlp = new CStackInstance(creId, amount);
|
|
|
//will be set during initialization
|
|
|
guard->putStack(SlotID(0), hlp);
|
|
|
@@ -670,10 +671,11 @@ bool CRmgTemplateZone::createTreasurePile (CMapGenerator* gen, int3 &pos)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ ui32 desiredValue = gen->rand.nextInt(minValue, maxValue);
|
|
|
|
|
|
int currentValue = 0;
|
|
|
CGObjectInstance * object = nullptr;
|
|
|
- while (currentValue < minValue)
|
|
|
+ while (currentValue < desiredValue)
|
|
|
{
|
|
|
treasures[info.nextTreasurePos] = nullptr;
|
|
|
|
|
|
@@ -697,21 +699,22 @@ bool CRmgTemplateZone::createTreasurePile (CMapGenerator* gen, int3 &pos)
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- int remaining = maxValue - currentValue;
|
|
|
-
|
|
|
- ObjectInfo oi = getRandomObject(gen, info, remaining);
|
|
|
- object = oi.generateObject();
|
|
|
- if (!object)
|
|
|
+ ObjectInfo oi = getRandomObject(gen, info, desiredValue - currentValue);
|
|
|
+ if (!oi.value) //0 value indicates no object
|
|
|
{
|
|
|
vstd::erase_if_present(treasures, info.nextTreasurePos);
|
|
|
break;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
+ object = oi.generateObject();
|
|
|
+
|
|
|
//remove from possible objects
|
|
|
auto oiptr = std::find(possibleObjects.begin(), possibleObjects.end(), oi);
|
|
|
assert (oiptr != possibleObjects.end());
|
|
|
oiptr->maxPerZone--;
|
|
|
+ if (!oiptr->maxPerZone)
|
|
|
+ possibleObjects.erase(oiptr);
|
|
|
//TODO
|
|
|
|
|
|
//update treasure pile area
|
|
|
@@ -730,34 +733,38 @@ bool CRmgTemplateZone::createTreasurePile (CMapGenerator* gen, int3 &pos)
|
|
|
info.blockedPositions.insert(blockPos);
|
|
|
}
|
|
|
info.occupiedPositions.insert(visitablePos);
|
|
|
- }
|
|
|
|
|
|
- currentValue += oi.value;
|
|
|
+ currentValue += oi.value;
|
|
|
|
|
|
- treasures[info.nextTreasurePos] = object;
|
|
|
+ treasures[info.nextTreasurePos] = object;
|
|
|
|
|
|
- //now find place for next object
|
|
|
- int3 placeFound(-1,-1,-1);
|
|
|
+ //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
|
|
|
+ //randomize next position from among possible ones
|
|
|
+ std::vector<int3> boundaryCopy (boundary.begin(), boundary.end());
|
|
|
+ RandomGeneratorUtil::randomShuffle(boundaryCopy, gen->rand);
|
|
|
+
|
|
|
+ for (auto tile : boundaryCopy)
|
|
|
{
|
|
|
- bool here = true;
|
|
|
- gen->foreach_neighbour (tile, [gen, &here](int3 pos)
|
|
|
+ if (gen->isPossible(tile)) //we can place new treasure only on possible tile
|
|
|
{
|
|
|
- if (!(gen->isBlocked(pos) || gen->isPossible(pos)))
|
|
|
- here = false;
|
|
|
- });
|
|
|
- if (here)
|
|
|
- {
|
|
|
- placeFound = tile;
|
|
|
- break;
|
|
|
+ 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())
|
|
|
- info.nextTreasurePos = placeFound;
|
|
|
+ if (placeFound.valid())
|
|
|
+ info.nextTreasurePos = placeFound;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
if (treasures.size())
|
|
|
@@ -865,6 +872,8 @@ bool CRmgTemplateZone::createTreasurePile (CMapGenerator* gen, int3 &pos)
|
|
|
{
|
|
|
if (gen->isPossible(treasure.first))
|
|
|
gen->setOccupied (treasure.first, ETileType::BLOCKED);
|
|
|
+
|
|
|
+ delete treasure.second;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -1077,7 +1086,8 @@ bool CRmgTemplateZone::createRequiredObjects(CMapGenerator* gen)
|
|
|
|
|
|
void CRmgTemplateZone::createTreasures(CMapGenerator* gen)
|
|
|
{
|
|
|
- const double minDistance = std::max<float>(15.0f / sqrt(totalDensity), 2);
|
|
|
+ //this is squared distance for optimization purposes
|
|
|
+ const double minDistance = std::max<float>(200.f / totalDensity, 4);
|
|
|
//distance lower than 2 causes objects to overlap and crash
|
|
|
|
|
|
do {
|
|
|
@@ -1230,7 +1240,7 @@ bool CRmgTemplateZone::findPlaceForTreasurePile(CMapGenerator* gen, float min_di
|
|
|
bool allTilesAvailable = true;
|
|
|
gen->foreach_neighbour (tile, [&gen, &allTilesAvailable](int3 neighbour)
|
|
|
{
|
|
|
- if (!(gen->isPossible(neighbour) || gen->isBlocked(neighbour)))
|
|
|
+ if (!(gen->isPossible(neighbour) || gen->shouldBeBlocked(neighbour)))
|
|
|
{
|
|
|
allTilesAvailable = false; //all present tiles must be already blocked or ready for new objects
|
|
|
}
|
|
|
@@ -1488,19 +1498,20 @@ bool CRmgTemplateZone::guardObject(CMapGenerator* gen, CGObjectInstance* object,
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
-ObjectInfo CRmgTemplateZone::getRandomObject (CMapGenerator* gen, CTreasurePileInfo &info, ui32 value)
|
|
|
+ObjectInfo CRmgTemplateZone::getRandomObject (CMapGenerator* gen, CTreasurePileInfo &info, ui32 remaining)
|
|
|
{
|
|
|
//int objectsVisitableFromBottom = 0; //for debug
|
|
|
|
|
|
std::vector<std::pair<ui32, ObjectInfo>> tresholds;
|
|
|
ui32 total = 0;
|
|
|
|
|
|
- ui32 minValue = 0.25f * value;
|
|
|
+ //calculate actual treasure value range based on remaining value
|
|
|
+ ui32 minValue = 0.25f * remaining;
|
|
|
|
|
|
//roulette wheel
|
|
|
for (ObjectInfo &oi : possibleObjects) //copy constructor turned out to be costly
|
|
|
{
|
|
|
- if (oi.value >= minValue && oi.value <= value && oi.maxPerZone > 0)
|
|
|
+ if (oi.value >= minValue && oi.value <= remaining && oi.maxPerZone > 0)
|
|
|
{
|
|
|
int3 newVisitableOffset = oi.templ.getVisitableOffset(); //visitablePos assumes object will be shifter by visitableOffset
|
|
|
int3 newVisitablePos = info.nextTreasurePos;
|
|
|
@@ -1590,16 +1601,17 @@ ObjectInfo CRmgTemplateZone::getRandomObject (CMapGenerator* gen, CTreasurePileI
|
|
|
continue;
|
|
|
|
|
|
total += oi.probability;
|
|
|
+ //assert (oi.value > 0);
|
|
|
tresholds.push_back (std::make_pair (total, oi));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//logGlobal->infoStream() << boost::format ("Number of objects visitable from bottom: %d") % objectsVisitableFromBottom;
|
|
|
|
|
|
- //Generate pandora Box with gold if the value is extremely high
|
|
|
- ObjectInfo oi;
|
|
|
if (tresholds.empty())
|
|
|
{
|
|
|
+ ObjectInfo oi;
|
|
|
+ //Generate pandora Box with gold if the value is extremely high
|
|
|
if (minValue > 20000) //we don't have object valuable enough
|
|
|
{
|
|
|
oi.generateObject = [minValue]() -> CGObjectInstance *
|
|
|
@@ -1614,25 +1626,28 @@ ObjectInfo CRmgTemplateZone::getRandomObject (CMapGenerator* gen, CTreasurePileI
|
|
|
oi.value = minValue;
|
|
|
oi.probability = 0;
|
|
|
}
|
|
|
- else
|
|
|
+ else //generate empty object with 0 value if the value if we can't spawn anything
|
|
|
{
|
|
|
oi.generateObject = [gen]() -> CGObjectInstance *
|
|
|
{
|
|
|
return nullptr;
|
|
|
};
|
|
|
oi.setTemplate(Obj::PANDORAS_BOX, 0, terrainType); //TODO: null template or something? should be never used, but hell knows
|
|
|
- oi.value = 0;
|
|
|
+ oi.value = 0; // this field is checked to determine no object
|
|
|
oi.probability = 0;
|
|
|
}
|
|
|
return oi;
|
|
|
}
|
|
|
-
|
|
|
- int r = gen->rand.nextInt (1, total);
|
|
|
-
|
|
|
- for (auto t : tresholds)
|
|
|
+ else
|
|
|
{
|
|
|
- if (r <= t.first)
|
|
|
- return t.second;
|
|
|
+ int r = gen->rand.nextInt (1, total);
|
|
|
+
|
|
|
+ for (auto t : tresholds)
|
|
|
+ {
|
|
|
+ if (r <= t.first)
|
|
|
+ return t.second;
|
|
|
+ }
|
|
|
+ assert (0); //we should never be here
|
|
|
}
|
|
|
//FIXME: control reaches end of non-void function. Missing return?
|
|
|
}
|