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

Rmg water support (#751)

* Roads added to shipyard
* Load general rmg parameters from config
* Fix issue with default zone guard
* Move magic numbers related to balance to randomMap.json
This commit is contained in:
Nordsoft91 2022-06-05 09:02:58 +03:00 committed by Andrii Danylchenko
parent 5c1a66ab69
commit 5054ee011a
8 changed files with 323 additions and 128 deletions

59
config/randomMap.json Normal file
View File

@ -0,0 +1,59 @@
{
"terrain" :
{
"undergroundAllow" : ["lava"], //others to be replaced by subterranena
"groundProhibit" : ["subterranean"] //to be replaced by dirt
},
"waterZone" :
{
"treasure" :
[
{ "min" : 2000, "max" : 6000, "density" : 1 },
{ "min" : 100, "max" : 1000, "density" : 5 }
],
"shipyard" :
{
"value" : 3500
}
},
"mines" :
{
"value" :
{
"wood" : 1500,
"ore" : 1500,
"gems" : 3500,
"crystal" : 3500,
"mercury" : 3500,
"sulfur" : 3500,
"gold" : 7000
},
"extraResourcesLimit" : 3
},
"minGuardStrength" : 2000,
"defaultRoadType" : "cobblestone_road",
"treasureValueLimit" : 20000, //generate pandora with gold for treasure above this limit
"prisons" :
{
"experience" : [0, 5000, 15000, 90000, 500000],
"value" : [2500, 5000, 10000, 20000, 30000],
},
"scrolls" :
{
"value" : [500, 2000, 3000, 4000, 5000],
},
"pandoras" :
{
"valueMultiplierGold" : 5000,
"valueMultiplierExperience" : 6000,
"valueMultiplierSpells" : 2500,
"valueSpellSchool" : 15000,
"valueSpell60" : 30000,
"creaturesValue" : [5000, 7000, 9000, 12000, 16000, 21000, 27000]
},
"quests" :
{
"value" : [2000, 5333, 8666, 12000],
"rewardValue" : [5000, 10000, 15000, 20000]
}
}

View File

@ -60,6 +60,12 @@
"minimum" : 0
}
}
},
"waterContent":
{
"enum": ["none", "normal", "islands"],
"additionalProperties" : false,
"type": "string"
}
},
@ -73,6 +79,10 @@
"type": "array",
"items":{"$ref" : "#/definitions/connection"}
},
"allowedWaterContent": {
"type": "array",
"items": {"$ref" : "#/definitions/waterContent"}
},
"required" : ["zones", "connections"],
"additionalProperties" : false
}

View File

@ -246,7 +246,7 @@ void CMapGenOptions::finalize(CRandomGenerator & rand)
if(waterContent == EWaterContent::RANDOM)
{
waterContent = static_cast<EWaterContent::EWaterContent>(rand.nextInt(EWaterContent::NONE, EWaterContent::ISLANDS));
waterContent = *RandomGeneratorUtil::nextItem(mapTemplate->getWaterContentAllowed(), rand);
}
if(monsterStrength == EMonsterStrength::RANDOM)
{

View File

@ -62,10 +62,89 @@ CMapGenerator::CMapGenerator(CMapGenOptions& mapGenOptions, int RandomSeed) :
zonesTotal(0), tiles(nullptr), prisonsRemaining(0),
monolithIndex(0)
{
loadConfig();
rand.setSeed(this->randomSeed);
mapGenOptions.finalize(rand);
}
void CMapGenerator::loadConfig()
{
static std::map<std::string, ETerrainType> terrainMap
{
{"dirt", ETerrainType::DIRT},
{"sand", ETerrainType::SAND},
{"grass", ETerrainType::GRASS},
{"snow", ETerrainType::SNOW},
{"swamp", ETerrainType::SWAMP},
{"subterranean", ETerrainType::SUBTERRANEAN},
{"lava", ETerrainType::LAVA},
{"rough", ETerrainType::ROUGH}
};
static const std::map<std::string, Res::ERes> resMap
{
{"wood", Res::ERes::WOOD},
{"ore", Res::ERes::ORE},
{"gems", Res::ERes::GEMS},
{"crystal", Res::ERes::CRYSTAL},
{"mercury", Res::ERes::MERCURY},
{"sulfur", Res::ERes::SULFUR},
{"gold", Res::ERes::GOLD},
};
static std::map<std::string, ERoadType::ERoadType> roadTypeMap
{
{"dirt_road", ERoadType::DIRT_ROAD},
{"gravel_road", ERoadType::GRAVEL_ROAD},
{"cobblestone_road", ERoadType::COBBLESTONE_ROAD}
};
static const ResourceID path("config/randomMap.json");
JsonNode randomMapJson(path);
for(auto& s : randomMapJson["terrain"]["undergroundAllow"].Vector())
{
if(!s.isNull())
config.terrainUndergroundAllowed.push_back(terrainMap[s.String()]);
}
for(auto& s : randomMapJson["terrain"]["groundProhibit"].Vector())
{
if(!s.isNull())
config.terrainGroundProhibit.push_back(terrainMap[s.String()]);
}
config.shipyardGuard = randomMapJson["waterZone"]["shipyard"]["value"].Integer();
for(auto & treasure : randomMapJson["waterZone"]["treasure"].Vector())
{
config.waterTreasure.emplace_back(treasure["min"].Integer(), treasure["max"].Integer(), treasure["density"].Integer());
}
for(auto& s : resMap)
{
config.mineValues[s.second] = randomMapJson["mines"]["value"][s.first].Integer();
}
config.mineExtraResources = randomMapJson["mines"]["extraResourcesLimit"].Integer();
config.minGuardStrength = randomMapJson["minGuardStrength"].Integer();
config.defaultRoadType = roadTypeMap[randomMapJson["defaultRoadType"].String()];
config.treasureValueLimit = randomMapJson["treasureValueLimit"].Integer();
for(auto & i : randomMapJson["prisons"]["experience"].Vector())
config.prisonExperience.push_back(i.Integer());
for(auto & i : randomMapJson["prisons"]["value"].Vector())
config.prisonValues.push_back(i.Integer());
for(auto & i : randomMapJson["scrolls"]["value"].Vector())
config.scrollValues.push_back(i.Integer());
for(auto & i : randomMapJson["pandoras"]["creaturesValue"].Vector())
config.pandoraCreatureValues.push_back(i.Integer());
for(auto & i : randomMapJson["quests"]["value"].Vector())
config.questValues.push_back(i.Integer());
for(auto & i : randomMapJson["quests"]["rewardValue"].Vector())
config.questRewardValues.push_back(i.Integer());
config.pandoraMultiplierGold = randomMapJson["pandoras"]["valueMultiplierGold"].Integer();
config.pandoraMultiplierExperience = randomMapJson["pandoras"]["valueMultiplierExperience"].Integer();
config.pandoraMultiplierSpells = randomMapJson["pandoras"]["valueMultiplierSpells"].Integer();
config.pandoraSpellSchool = randomMapJson["pandoras"]["valueSpellSchool"].Integer();
config.pandoraSpell60 = randomMapJson["pandoras"]["valueSpell60"].Integer();
}
const CMapGenerator::Config & CMapGenerator::getConfig() const
{
return config;
}
void CMapGenerator::initTiles()
{
map->initTerrain();
@ -309,8 +388,10 @@ void CMapGenerator::genZones()
void CMapGenerator::createWaterTreasures()
{
//add treasures on water
getZoneWater().second->addTreasureInfo(CTreasureInfo{100, 1000, 5});
getZoneWater().second->addTreasureInfo(CTreasureInfo{2000, 6000, 1});
for(auto & treasureInfo : getConfig().waterTreasure)
{
getZoneWater().second->addTreasureInfo(treasureInfo);
}
}
void CMapGenerator::prepareWaterTiles()

View File

@ -52,11 +52,31 @@ public:
class DLL_LINKAGE CMapGenerator
{
public:
struct Config
{
std::vector<ETerrainType> terrainUndergroundAllowed;
std::vector<ETerrainType> terrainGroundProhibit;
std::vector<CTreasureInfo> waterTreasure;
int shipyardGuard;
int mineExtraResources;
std::map<Res::ERes, int> mineValues;
int minGuardStrength;
ERoadType::ERoadType defaultRoadType;
int treasureValueLimit;
std::vector<int> prisonExperience, prisonValues;
std::vector<int> scrollValues;
int pandoraMultiplierGold, pandoraMultiplierExperience, pandoraMultiplierSpells, pandoraSpellSchool, pandoraSpell60;
std::vector<int> pandoraCreatureValues;
std::vector<int> questValues, questRewardValues;
};
using Zones = std::map<TRmgTemplateZoneId, std::shared_ptr<CRmgTemplateZone>>;
explicit CMapGenerator(CMapGenOptions& mapGenOptions, int RandomSeed = std::time(nullptr));
~CMapGenerator(); // required due to std::unique_ptr
const Config & getConfig() const;
mutable std::unique_ptr<CMap> map;
CRandomGenerator rand;
@ -111,6 +131,7 @@ public:
private:
int randomSeed;
CMapGenOptions& mapGenOptions;
Config config;
std::vector<rmg::ZoneConnection> connectionsLeft;
Zones zones;
@ -129,6 +150,8 @@ private:
void checkIsOnMap(const int3 &tile) const; //throws
/// Generation methods
void loadConfig();
std::string getMapDescription() const;
void initPrisonsRemaining();

View File

@ -10,6 +10,7 @@
#include "StdInc.h"
#include <vstd/ContainerUtils.h>
#include <boost/bimap.hpp>
#include "CRmgTemplate.h"
#include "../mapping/CMap.h"
@ -359,7 +360,7 @@ void ZoneOptions::serializeJson(JsonSerializeFormat & handler)
rawStrength = static_cast<decltype(rawStrength)>(zoneMonsterStrength);
rawStrength++;
}
handler.serializeEnum("monsters", rawStrength, STRENGTH);
handler.serializeEnum("monsters", rawStrength, EMonsterStrength::ZONE_NORMAL + 1, STRENGTH);
if(!handler.saving)
{
rawStrength--;
@ -443,6 +444,11 @@ bool CRmgTemplate::isWaterContentAllowed(EWaterContent::EWaterContent waterConte
return waterContent == EWaterContent::EWaterContent::RANDOM || allowedWaterContent.count(waterContent);
}
const std::set<EWaterContent::EWaterContent> & CRmgTemplate::getWaterContentAllowed() const
{
return allowedWaterContent;
}
void CRmgTemplate::setId(const std::string & value)
{
id = value;
@ -583,6 +589,32 @@ void CRmgTemplate::serializeJson(JsonSerializeFormat & handler)
auto connectionsData = handler.enterArray("connections");
connectionsData.serializeStruct(connections);
}
{
boost::bimap<EWaterContent::EWaterContent, std::string> enc;
enc.insert({EWaterContent::NONE, "none"});
enc.insert({EWaterContent::NORMAL, "normal"});
enc.insert({EWaterContent::ISLANDS, "islands"});
JsonNode node;
if(handler.saving)
{
node.setType(JsonNode::JsonType::DATA_VECTOR);
for(auto wc : allowedWaterContent)
{
JsonNode n;
n.String() = enc.left.at(wc);
node.Vector().push_back(n);
}
}
handler.serializeRaw("allowedWaterContent", node, boost::none);
if(!handler.saving)
{
for(auto wc : node.Vector())
{
allowedWaterContent.insert(enc.right.at(std::string(wc.String())));
}
}
}
{
auto zonesData = handler.enterStruct("zones");

View File

@ -181,6 +181,7 @@ public:
bool matchesSize(const int3 & value) const;
bool isWaterContentAllowed(EWaterContent::EWaterContent waterContent) const;
const std::set<EWaterContent::EWaterContent> & getWaterContentAllowed() const;
void setId(const std::string & value);
const std::string & getName() const;

View File

@ -641,7 +641,7 @@ void CRmgTemplateZone::waterConnection(CRmgTemplateZone& dst)
if(dst.getType() == ETemplateZoneType::PLAYER_START || dst.getType() == ETemplateZoneType::CPU_START || zoneTowns)
{
coastTile = dst.createShipyard(lake.tiles, 3500);
coastTile = dst.createShipyard(lake.tiles, gen->getConfig().shipyardGuard);
if(!coastTile.valid())
{
coastTile = makeBoat(dst.getId(), lake.tiles);
@ -1266,7 +1266,7 @@ bool CRmgTemplateZone::addMonster(int3 &pos, si32 strength, bool clearSurroundin
int strength2 = static_cast<int>(std::max(0.f, (strength - value2[monsterStrength]) * multiplier2[monsterStrength]));
strength = strength1 + strength2;
if (strength < 2000)
if (strength < gen->getConfig().minGuardStrength)
return false; //no guard at all
CreatureID creId = CreatureID::NONE;
@ -1742,14 +1742,14 @@ void CRmgTemplateZone::initTerrainType ()
//TODO: allow new types of terrain?
{
if (isUnderground())
if(isUnderground())
{
if (terrainType != ETerrainType::LAVA)
if(!vstd::contains(gen->getConfig().terrainUndergroundAllowed, terrainType))
terrainType = ETerrainType::SUBTERRANEAN;
}
else
{
if (terrainType == ETerrainType::SUBTERRANEAN)
if(vstd::contains(gen->getConfig().terrainGroundProhibit, terrainType))
terrainType = ETerrainType::DIRT;
}
}
@ -1767,8 +1767,6 @@ void CRmgTemplateZone::paintZoneTerrain (ETerrainType terrainType)
bool CRmgTemplateZone::placeMines ()
{
using namespace Res;
static const std::map<ERes, int> mineValue{{ERes::WOOD, 1500}, {ERes::ORE, 1500}, {ERes::GEMS, 3500}, {ERes::CRYSTAL, 3500}, {ERes::MERCURY, 3500}, {ERes::SULFUR, 3500}, {ERes::GOLD, 7000}};
std::vector<CGMine*> createdMines;
for(const auto & mineInfo : mines)
@ -1783,22 +1781,26 @@ bool CRmgTemplateZone::placeMines ()
createdMines.push_back(mine);
if(!i && (res == ERes::WOOD || res == ERes::ORE))
addCloseObject(mine, mineValue.at(res)); //only first woor&ore mines are close
addCloseObject(mine, gen->getConfig().mineValues.at(res)); //only first wood&ore mines are close
else
addRequiredObject(mine, mineValue.at(res));
addRequiredObject(mine, gen->getConfig().mineValues.at(res));
}
}
//create extra resources
for(auto * mine : createdMines)
if(int extraRes = gen->getConfig().mineExtraResources)
{
for(int rc = gen->rand.nextInt(1, 3); rc > 0; --rc)
for(auto * mine : createdMines)
{
auto resourse = (CGResource*) VLC->objtypeh->getHandlerFor(Obj::RESOURCE, mine->producedResource)->create(ObjectTemplate());
resourse->amount = CGResource::RANDOM_AMOUNT;
addNearbyObject(resourse, mine);
for(int rc = gen->rand.nextInt(1, extraRes); rc > 0; --rc)
{
auto resourse = (CGResource*) VLC->objtypeh->getHandlerFor(Obj::RESOURCE, mine->producedResource)->create(ObjectTemplate());
resourse->amount = CGResource::RANDOM_AMOUNT;
addNearbyObject(resourse, mine);
}
}
}
return true;
}
@ -2072,69 +2074,62 @@ bool CRmgTemplateZone::createShipyard(const int3 & position, si32 guardStrength)
shipyard->tempOwner = PlayerColor::NEUTRAL;
setTemplateForObject(shipyard);
std::vector<int3> offsets;
std::vector<int3> outOffsets;
auto tilesBlockedByObject = shipyard->getBlockedOffsets();
tilesBlockedByObject.insert(shipyard->getVisitableOffset());
shipyard->getOutOffsets(offsets);
shipyard->getOutOffsets(outOffsets);
int3 targetTile(-1, -1, -1);
std::set<int3> shipAccessCandidates;
for(auto& candidateTile : possibleTiles)
for(const auto & outOffset : outOffsets)
{
bool foundTargetPosition = false;
for(const auto & offset : offsets)
auto candidateTile = position - outOffset;
std::set<int3> tilesBlockedAbsolute;
//check space under object
bool allClear = true;
for(const auto & objectTileOffset : tilesBlockedByObject)
{
if(candidateTile+offset == position)
auto objectTile = candidateTile + objectTileOffset;
tilesBlockedAbsolute.insert(objectTile);
if(!gen->map->isInTheMap(objectTile) || !gen->isPossible(objectTile) || gen->getZoneID(objectTile)!=id)
{
std::set<int3> tilesBlockedAbsolute;
//check space under object
bool allClear = true;
for(const auto & objectTileOffset : tilesBlockedByObject)
{
auto objectTile = candidateTile + objectTileOffset;
tilesBlockedAbsolute.insert(objectTile);
if(!gen->map->isInTheMap(objectTile) || !gen->isPossible(objectTile) || gen->getZoneID(objectTile)!=id)
{
allClear = false;
break;
}
}
if(!allClear) //cannot place shipyard anyway
break;
//prepare temporary map
for(auto& blockedPos : tilesBlockedAbsolute)
gen->setOccupied(blockedPos, ETileType::USED);
//check if position is accessible
gen->foreach_neighbour(position, [this, &shipAccessCandidates](const int3 & v)
{
if(!gen->isBlocked(v) && gen->getZoneID(v)==id)
{
//make sure that it's possible to create path to boarding position
if(crunchPath(v, findClosestTile(freePaths, v), false, nullptr))
shipAccessCandidates.insert(v);
}
});
//rollback temporary map
for(auto& blockedPos : tilesBlockedAbsolute)
gen->setOccupied(blockedPos, ETileType::POSSIBLE);
if(!shipAccessCandidates.empty())
{
foundTargetPosition = true;
}
break; //no need to check other offsets as we already found position
allClear = false;
break;
}
}
if(!allClear) //cannot place shipyard anyway
continue;
if(foundTargetPosition && isAccessibleFromSomewhere(shipyard->appearance, candidateTile))
//prepare temporary map
for(auto& blockedPos : tilesBlockedAbsolute)
gen->setOccupied(blockedPos, ETileType::USED);
//check if boarding position is accessible
gen->foreach_neighbour(position, [this, &shipAccessCandidates](const int3 & v)
{
if(!gen->isBlocked(v) && gen->getZoneID(v)==id)
{
//make sure that it's possible to create path to boarding position
if(connectWithCenter(v, false, false))
shipAccessCandidates.insert(v);
}
});
//check if we can connect shipyard entrance with path
if(!connectWithCenter(candidateTile + shipyard->getVisitableOffset(), false))
shipAccessCandidates.clear();
//rollback temporary map
for(auto& blockedPos : tilesBlockedAbsolute)
gen->setOccupied(blockedPos, ETileType::POSSIBLE);
if(!shipAccessCandidates.empty() && isAccessibleFromSomewhere(shipyard->appearance, candidateTile))
{
targetTile = candidateTile;
break;
break; //no need to check other offsets as we already found position
}
shipAccessCandidates.clear(); //invalidate positions
@ -2146,19 +2141,24 @@ bool CRmgTemplateZone::createShipyard(const int3 & position, si32 guardStrength)
return false;
}
placeObject(shipyard, targetTile);
guardObject(shipyard, guardStrength, false, true);
for(auto& accessPosition : shipAccessCandidates)
if(tryToPlaceObjectAndConnectToPath(shipyard, targetTile)==EObjectPlacingResult::SUCCESS)
{
if(connectPath(accessPosition, false))
placeObject(shipyard, targetTile);
guardObject(shipyard, guardStrength, false, true);
for(auto& accessPosition : shipAccessCandidates)
{
gen->setOccupied(accessPosition, ETileType::FREE);
return true;
if(connectPath(accessPosition, false))
{
gen->setOccupied(accessPosition, ETileType::FREE);
return true;
}
}
}
throw rmgException("Cannot find path to shipyard boarding position");
logGlobal->warn("Cannot find path to shipyard boarding position");
delete shipyard;
return false;
}
void CRmgTemplateZone::createTreasures()
@ -2206,7 +2206,12 @@ void CRmgTemplateZone::createTreasures()
//optimization - don't check tiles which are not allowed
vstd::erase_if(possibleTiles, [this](const int3 &tile) -> bool
{
return (!gen->isPossible(tile)) || gen->getZoneID(tile)!=getId();
//for water area we sholdn't place treasures close to coast
for(auto & lake : lakes)
if(vstd::contains(lake.distance, tile) && lake.distance[tile] < 2)
return true;
return !gen->isPossible(tile) || gen->getZoneID(tile)!=getId();
});
@ -2376,7 +2381,7 @@ void CRmgTemplateZone::drawRoads()
}
gen->getEditManager()->getTerrainSelection().setSelection(tiles);
gen->getEditManager()->drawRoad(ERoadType::COBBLESTONE_ROAD, &gen->rand);
gen->getEditManager()->drawRoad(gen->getConfig().defaultRoadType, &gen->rand);
}
@ -2386,26 +2391,13 @@ bool CRmgTemplateZone::fill()
addAllPossibleObjects();
if(type==ETemplateZoneType::WATER)
{
initFreeTiles();
connectLater();
createRequiredObjects();
fractalize();
createTreasures();
}
else
{
//zone center should be always clear to allow other tiles to connect
initFreeTiles();
connectLater(); //ideally this should work after fractalize, but fails
fractalize();
placeMines();
createRequiredObjects();
createTreasures();
}
gen->dump(false);
//zone center should be always clear to allow other tiles to connect
initFreeTiles();
connectLater(); //ideally this should work after fractalize, but fails
fractalize();
placeMines();
createRequiredObjects();
createTreasures();
logGlobal->info("Zone %d filled successfully", id);
return true;
@ -2613,6 +2605,7 @@ void CRmgTemplateZone::placeObject(CGObjectInstance* object, const int3 &pos, bo
case Obj::MONOLITH_ONE_WAY_ENTRANCE:
case Obj::MONOLITH_ONE_WAY_EXIT:
case Obj::SUBTERRANEAN_GATE:
case Obj::SHIPYARD:
{
addRoadNode(object->visitablePos());
}
@ -2831,11 +2824,11 @@ ObjectInfo CRmgTemplateZone::getRandomObject(CTreasurePileInfo &info, ui32 desir
}
}
if (thresholds.empty())
if(thresholds.empty())
{
ObjectInfo oi;
//Generate pandora Box with gold if the value is extremely high
if (minValue > 20000) //we don't have object valuable enough
if(minValue > gen->getConfig().treasureValueLimit) //we don't have object valuable enough
{
oi.generateObject = [minValue]() -> CGObjectInstance *
{
@ -2913,17 +2906,15 @@ void CRmgTemplateZone::addAllPossibleObjects()
//prisons
//levels 1, 5, 10, 20, 30
static int prisonExp[] = { 0, 5000, 15000, 90000, 500000 };
static int prisonValues[] = { 2500, 5000, 10000, 20000, 30000 };
for (int i = 0; i < 5; i++)
static int prisonsLevels = std::min(gen->getConfig().prisonExperience.size(), gen->getConfig().prisonValues.size());
for(int i = 0; i < prisonsLevels; i++)
{
oi.generateObject = [i, this]() -> CGObjectInstance *
{
std::vector<ui32> possibleHeroes;
for (int j = 0; j < gen->map->allowedHeroes.size(); j++)
for(int j = 0; j < gen->map->allowedHeroes.size(); j++)
{
if (gen->map->allowedHeroes[j])
if(gen->map->allowedHeroes[j])
possibleHeroes.push_back(j);
}
@ -2933,7 +2924,7 @@ void CRmgTemplateZone::addAllPossibleObjects()
obj->subID = hid; //will be initialized later
obj->exp = prisonExp[i];
obj->exp = gen->getConfig().prisonExperience[i];
obj->setOwner(PlayerColor::NEUTRAL);
gen->map->allowedHeroes[hid] = false; //ban this hero
gen->decreasePrisonsRemaining();
@ -2942,7 +2933,7 @@ void CRmgTemplateZone::addAllPossibleObjects()
return obj;
};
oi.setTemplate(Obj::PRISON, 0, terrainType);
oi.value = prisonValues[i];
oi.value = gen->getConfig().prisonValues[i];
oi.probability = 30;
oi.maxPerZone = gen->getPrisonsRemaning() / 5; //probably not perfect, but we can't generate more prisons than hereos.
possibleObjects.push_back(oi);
@ -3008,9 +2999,7 @@ void CRmgTemplateZone::addAllPossibleObjects()
}
}
static const int scrollValues[] = { 500, 2000, 3000, 4000, 5000 };
for (int i = 0; i < 5; i++)
for(int i = 0; i < gen->getConfig().scrollValues.size(); i++)
{
oi.generateObject = [i, this]() -> CGObjectInstance *
{
@ -3030,13 +3019,13 @@ void CRmgTemplateZone::addAllPossibleObjects()
return obj;
};
oi.setTemplate(Obj::SPELL_SCROLL, 0, terrainType);
oi.value = scrollValues[i];
oi.value = gen->getConfig().scrollValues[i];
oi.probability = 30;
possibleObjects.push_back(oi);
}
//pandora box with gold
for (int i = 1; i < 5; i++)
for(int i = 1; i < 5; i++)
{
oi.generateObject = [i]() -> CGObjectInstance *
{
@ -3046,7 +3035,7 @@ void CRmgTemplateZone::addAllPossibleObjects()
return obj;
};
oi.setTemplate(Obj::PANDORAS_BOX, 0, terrainType);
oi.value = i * 5000;
oi.value = i * gen->getConfig().pandoraMultiplierGold;
oi.probability = 5;
possibleObjects.push_back(oi);
}
@ -3062,20 +3051,22 @@ void CRmgTemplateZone::addAllPossibleObjects()
return obj;
};
oi.setTemplate(Obj::PANDORAS_BOX, 0, terrainType);
oi.value = i * 6000;
oi.value = i * gen->getConfig().pandoraMultiplierExperience;
oi.probability = 20;
possibleObjects.push_back(oi);
}
//pandora box with creatures
static const int tierValues[] = { 5000, 7000, 9000, 12000, 16000, 21000, 27000 };
const std::vector<int> & tierValues = gen->getConfig().pandoraCreatureValues;
auto creatureToCount = [](CCreature * creature) -> int
auto creatureToCount = [&tierValues](CCreature * creature) -> int
{
if (!creature->AIValue) //bug #2681
return 0; //this box won't be generated
int actualTier = creature->level > 7 ? 6 : creature->level - 1;
int actualTier = creature->level > tierValues.size() ?
tierValues.size() - 1 :
creature->level - 1;
float creaturesAmount = ((float)tierValues[actualTier]) / creature->AIValue;
if (creaturesAmount <= 5)
{
@ -3142,7 +3133,7 @@ void CRmgTemplateZone::addAllPossibleObjects()
return obj;
};
oi.setTemplate(Obj::PANDORAS_BOX, 0, terrainType);
oi.value = (i + 1) * 2500; //5000 - 15000
oi.value = (i + 1) * gen->getConfig().pandoraMultiplierSpells; //5000 - 15000
oi.probability = 2;
possibleObjects.push_back(oi);
}
@ -3171,7 +3162,7 @@ void CRmgTemplateZone::addAllPossibleObjects()
return obj;
};
oi.setTemplate(Obj::PANDORAS_BOX, 0, terrainType);
oi.value = 15000;
oi.value = gen->getConfig().pandoraSpellSchool;
oi.probability = 2;
possibleObjects.push_back(oi);
}
@ -3199,7 +3190,7 @@ void CRmgTemplateZone::addAllPossibleObjects()
return obj;
};
oi.setTemplate(Obj::PANDORAS_BOX, 0, terrainType);
oi.value = 30000;
oi.value = gen->getConfig().pandoraSpell60;
oi.probability = 2;
possibleObjects.push_back(oi);
@ -3240,7 +3231,7 @@ void CRmgTemplateZone::addAllPossibleObjects()
return artInfo;
};
for (int i = 0; i < std::min((int)creatures.size(), questArtsRemaining - genericSeerHuts); i++)
for(int i = 0; i < std::min((int)creatures.size(), questArtsRemaining - genericSeerHuts); i++)
{
auto creature = creatures[i];
int creaturesAmount = creatureToCount(creature);
@ -3276,15 +3267,13 @@ void CRmgTemplateZone::addAllPossibleObjects()
possibleObjects.push_back(oi);
}
static int seerExpGold[] = { 5000, 10000, 15000, 20000 };
static int seerValues[] = { 2000, 5333, 8666, 12000 };
for (int i = 0; i < 4; i++) //seems that code for exp and gold reward is similiar
static int seerLevels = std::min(gen->getConfig().questValues.size(), gen->getConfig().questRewardValues.size());
for(int i = 0; i < seerLevels; i++) //seems that code for exp and gold reward is similiar
{
int randomAppearance = *RandomGeneratorUtil::nextItem(VLC->objtypeh->knownSubObjects(Obj::SEER_HUT), gen->rand);
oi.setTemplate(Obj::SEER_HUT, randomAppearance, terrainType);
oi.value = seerValues[i];
oi.value = gen->getConfig().questValues[i];
oi.probability = 10;
oi.generateObject = [i, randomAppearance, this, generateArtInfo]() -> CGObjectInstance *
@ -3294,7 +3283,7 @@ void CRmgTemplateZone::addAllPossibleObjects()
obj->rewardType = CGSeerHut::EXPERIENCE;
obj->rID = 0; //unitialized?
obj->rVal = seerExpGold[i];
obj->rVal = gen->getConfig().questRewardValues[i];
obj->quest->missionType = CQuest::MISSION_ART;
ArtifactID artid = *RandomGeneratorUtil::nextItem(gen->getQuestArtsRemaning(), gen->rand);
@ -3317,7 +3306,7 @@ void CRmgTemplateZone::addAllPossibleObjects()
auto obj = (CGSeerHut *) factory->create(ObjectTemplate());
obj->rewardType = CGSeerHut::RESOURCES;
obj->rID = Res::GOLD;
obj->rVal = seerExpGold[i];
obj->rVal = gen->getConfig().questRewardValues[i];
obj->quest->missionType = CQuest::MISSION_ART;
ArtifactID artid = *RandomGeneratorUtil::nextItem(gen->getQuestArtsRemaning(), gen->rand);