mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
- Implemented guard generation formula following this post http://forum.vcmi.eu/viewtopic.php?p=12426&sid=09f5fac8992dc880eb6a720615787ca0#12426
- Some primitive way to randomize treasures
This commit is contained in:
parent
6221f4ac2c
commit
62e9f13b08
@ -1709,7 +1709,7 @@ CRandomMapTab::CRandomMapTab()
|
||||
addButtonsWithRandToGroup(monsterStrengthGroup, monsterStrengthBtns, 0, 2, WIDE_BTN_WIDTH, 248, 251);
|
||||
monsterStrengthGroup->onChange = [&](int btnId)
|
||||
{
|
||||
mapGenOptions.setMonsterStrength(static_cast<EMonsterStrength::EMonsterStrength>(btnId));
|
||||
mapGenOptions.setMonsterStrength(static_cast<EMonsterStrength::EMonsterStrength>(btnId + EMonsterStrength::GLOBAL_WEAK)); //value 2 to 4
|
||||
};
|
||||
|
||||
// Show random maps btn
|
||||
|
@ -70,12 +70,12 @@
|
||||
},
|
||||
"connections" :
|
||||
[
|
||||
{ "a" : "1", "b" : "3", "guard" : 2000 },
|
||||
{ "a" : "1", "b" : "5", "guard" : 8000 },
|
||||
{ "a" : "2", "b" : "4", "guard" : 2000 },
|
||||
{ "a" : "2", "b" : "5", "guard" : 8000 },
|
||||
{ "a" : "3", "b" : "5", "guard" : 4000 },
|
||||
{ "a" : "4", "b" : "5", "guard" : 4000 }
|
||||
{ "a" : "1", "b" : "3", "guard" : 3000 },
|
||||
{ "a" : "1", "b" : "5", "guard" : 9000 },
|
||||
{ "a" : "2", "b" : "4", "guard" : 3000 },
|
||||
{ "a" : "2", "b" : "5", "guard" : 9000 },
|
||||
{ "a" : "3", "b" : "5", "guard" : 6000 },
|
||||
{ "a" : "4", "b" : "5", "guard" : 6000 }
|
||||
]
|
||||
},
|
||||
"Golden Ring" :
|
||||
@ -111,12 +111,12 @@
|
||||
},
|
||||
"connections" :
|
||||
[
|
||||
{ "a" : "1", "b" : "4", "guard" : 2000 },
|
||||
{ "a" : "1", "b" : "5", "guard" : 2000 },
|
||||
{ "a" : "2", "b" : "6", "guard" : 2000 },
|
||||
{ "a" : "2", "b" : "7", "guard" : 2000 },
|
||||
{ "a" : "3", "b" : "8", "guard" : 2000 },
|
||||
{ "a" : "3", "b" : "9", "guard" : 2000 },
|
||||
{ "a" : "1", "b" : "4", "guard" : 2500 },
|
||||
{ "a" : "1", "b" : "5", "guard" : 2500 },
|
||||
{ "a" : "2", "b" : "6", "guard" : 2500 },
|
||||
{ "a" : "2", "b" : "7", "guard" : 2500 },
|
||||
{ "a" : "3", "b" : "8", "guard" : 2500 },
|
||||
{ "a" : "3", "b" : "9", "guard" : 2500 },
|
||||
{ "a" : "4", "b" : "10", "guard" : 20000 },
|
||||
{ "a" : "5", "b" : "12", "guard" : 20000 },
|
||||
{ "a" : "6", "b" : "10", "guard" : 20000 },
|
||||
|
@ -216,11 +216,11 @@ void CMapGenOptions::finalize(CRandomGenerator & rand)
|
||||
|
||||
if(waterContent == EWaterContent::RANDOM)
|
||||
{
|
||||
waterContent = static_cast<EWaterContent::EWaterContent>(rand.nextInt(EWaterContent::LAST_ITEM));
|
||||
waterContent = static_cast<EWaterContent::EWaterContent>(rand.nextInt(EWaterContent::NONE, EWaterContent::ISLANDS));
|
||||
}
|
||||
if(monsterStrength == EMonsterStrength::RANDOM)
|
||||
{
|
||||
monsterStrength = static_cast<EMonsterStrength::EMonsterStrength>(rand.nextInt(EMonsterStrength::LAST_ITEM));
|
||||
monsterStrength = static_cast<EMonsterStrength::EMonsterStrength>(rand.nextInt(EMonsterStrength::GLOBAL_WEAK, EMonsterStrength::GLOBAL_STRONG));
|
||||
}
|
||||
|
||||
//rectangular maps are the future of gaming
|
||||
|
@ -23,8 +23,7 @@ namespace EWaterContent
|
||||
RANDOM = -1,
|
||||
NONE,
|
||||
NORMAL,
|
||||
ISLANDS,
|
||||
LAST_ITEM = ISLANDS
|
||||
ISLANDS
|
||||
};
|
||||
}
|
||||
|
||||
@ -32,11 +31,13 @@ namespace EMonsterStrength
|
||||
{
|
||||
enum EMonsterStrength
|
||||
{
|
||||
RANDOM = -1,
|
||||
WEAK,
|
||||
NORMAL,
|
||||
STRONG,
|
||||
LAST_ITEM = STRONG
|
||||
RANDOM = -2,
|
||||
ZONE_WEAK = -1,
|
||||
ZONE_NORMAL = 0,
|
||||
ZONE_STRONG = 1,
|
||||
GLOBAL_WEAK = 2,
|
||||
GLOBAL_NORMAL = 3,
|
||||
GLOBAL_STRONG = 4
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -258,6 +258,7 @@ void CMapGenerator::createConnections()
|
||||
});
|
||||
if (guardPos.valid())
|
||||
{
|
||||
setOccupied (guardPos, ETileType::FREE); //just in case monster is too weak to spawn
|
||||
zoneA->addMonster (this, guardPos, connection.getGuardStrength()); //TODO: set value according to template
|
||||
//zones can make paths only in their own area
|
||||
zoneA->crunchPath (this, guardPos, zoneA->getPos(), zoneA->getId()); //make connection towards our zone center
|
||||
|
@ -403,16 +403,38 @@ void CRmgTemplateZone::addRequiredObject(CGObjectInstance * obj, si32 strength)
|
||||
|
||||
void CRmgTemplateZone::addMonster(CMapGenerator* gen, int3 &pos, si32 strength)
|
||||
{
|
||||
//precalculate actual (randomized) monster strength based on this post
|
||||
//http://forum.vcmi.eu/viewtopic.php?p=12426#12426
|
||||
|
||||
int zoneMonsterStrength = 0; //TODO: range -1..1 based on template settings
|
||||
int mapMonsterStrength = gen->mapGenOptions->getMonsterStrength();
|
||||
int monsterStrength = zoneMonsterStrength + mapMonsterStrength - 1; //array index from 0 to 4
|
||||
static const int value1[] = {2500, 1500, 1000, 500, 0};
|
||||
static const int value2[] = {7500, 7500, 7500, 5000, 5000};
|
||||
static const float multiplier1[] = {0.5, 0.75, 1.0, 1.5, 1.5};
|
||||
static const float multiplier2[] = {0.5, 0.75, 1.0, 1.0, 1.5};
|
||||
|
||||
int strength1 = std::max(0.f, (strength - value1[monsterStrength]) * multiplier1[monsterStrength]);
|
||||
int strength2 = std::max(0.f, (strength - value2[monsterStrength]) * multiplier2[monsterStrength]);
|
||||
|
||||
strength = strength1 + strength2;
|
||||
if (strength < 2000)
|
||||
return; //no guard at all
|
||||
|
||||
CreatureID creId = CreatureID::NONE;
|
||||
int amount = 0;
|
||||
while (true)
|
||||
{
|
||||
creId = VLC->creh->pickRandomMonster(gen->rand);
|
||||
auto cre = VLC->creh->creatures[creId];
|
||||
amount = std::ceil((float)strength / cre->fightValue);
|
||||
if (strength >= cre->fightValue && amount >= cre->ammMin && amount <= 100) //at leats one full monster. size between minimum size of given stack and 100
|
||||
if ((cre->AIValue * (cre->ammMin + cre->ammMax) / 2 < strength) && (strength < cre->AIValue * 100)) //at leats one full monster. size between minimum size of given stack and 100
|
||||
{
|
||||
amount = strength / cre->AIValue;
|
||||
if (amount >= 4)
|
||||
amount *= gen->rand.nextDouble(0.75, 1.25);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto guard = new CGCreature();
|
||||
guard->ID = Obj::MONSTER;
|
||||
@ -424,6 +446,119 @@ void CRmgTemplateZone::addMonster(CMapGenerator* gen, int3 &pos, si32 strength)
|
||||
placeObject(gen, guard, pos);
|
||||
}
|
||||
|
||||
bool CRmgTemplateZone::createTreasurePile (CMapGenerator* gen, int3 &pos)
|
||||
{
|
||||
//TODO: read treasure values from template
|
||||
const int maxValue = 5000;
|
||||
const int minValue = 1500;
|
||||
|
||||
static const Res::ERes woodOre[] = {Res::ERes::WOOD, Res::ERes::ORE};
|
||||
static const Res::ERes preciousRes[] = {Res::ERes::CRYSTAL, Res::ERes::GEMS, Res::ERes::MERCURY, Res::ERes::SULFUR};
|
||||
static auto res_gen = gen->rand.getIntRange(Res::ERes::WOOD, Res::ERes::GOLD);
|
||||
|
||||
int currentValue = 0;
|
||||
CGObjectInstance * object = nullptr;
|
||||
while (currentValue < minValue)
|
||||
{
|
||||
int remaining = maxValue - currentValue;
|
||||
int nextValue = gen->rand.nextInt (0.25f * remaining, remaining);
|
||||
|
||||
if (nextValue >= 20000)
|
||||
{
|
||||
auto obj = new CGArtifact();
|
||||
obj->ID = Obj::RANDOM_RELIC_ART;
|
||||
obj->subID = 0;
|
||||
auto a = new CArtifactInstance(); //TODO: probably some refactoring could help here
|
||||
gen->map->addNewArtifactInstance(a);
|
||||
obj->storedArtifact = a;
|
||||
object = obj;
|
||||
currentValue += 20000;
|
||||
}
|
||||
else if (nextValue >= 10000)
|
||||
{
|
||||
auto obj = new CGArtifact();
|
||||
obj->ID = Obj::RANDOM_MAJOR_ART;
|
||||
obj->subID = 0;
|
||||
auto a = new CArtifactInstance();
|
||||
gen->map->addNewArtifactInstance(a);
|
||||
obj->storedArtifact = a;
|
||||
object = obj;
|
||||
currentValue += 10000;
|
||||
}
|
||||
else if (nextValue >= 5000)
|
||||
{
|
||||
auto obj = new CGArtifact();
|
||||
obj->ID = Obj::RANDOM_MINOR_ART;
|
||||
obj->subID = 0;
|
||||
auto a = new CArtifactInstance();
|
||||
gen->map->addNewArtifactInstance(a);
|
||||
obj->storedArtifact = a;
|
||||
object = obj;
|
||||
currentValue += 5000;
|
||||
}
|
||||
else if (nextValue >= 2000)
|
||||
{
|
||||
auto obj = new CGArtifact();
|
||||
obj->ID = Obj::RANDOM_TREASURE_ART;
|
||||
obj->subID = 0;
|
||||
auto a = new CArtifactInstance();
|
||||
gen->map->addNewArtifactInstance(a);
|
||||
obj->storedArtifact = a;
|
||||
object = obj;
|
||||
currentValue += 2000;
|
||||
}
|
||||
else if (nextValue >= 1500)
|
||||
{
|
||||
auto obj = new CGPickable();
|
||||
obj->ID = Obj::TREASURE_CHEST;
|
||||
obj->subID = 0;
|
||||
object = obj;
|
||||
currentValue += 1500;
|
||||
}
|
||||
else if (nextValue >= 1400)
|
||||
{
|
||||
auto obj = new CGResource();
|
||||
auto restype = static_cast<Res::ERes>(preciousRes[gen->rand.nextInt (0,3)]); //TODO: how about dedicated function to pick random element of array?
|
||||
obj->ID = Obj::RESOURCE;
|
||||
obj->subID = static_cast<si32>(restype);
|
||||
obj->amount = 0;
|
||||
object = obj;
|
||||
currentValue += 1400;
|
||||
}
|
||||
else if (nextValue >= 1000)
|
||||
{
|
||||
auto obj = new CGResource();
|
||||
auto restype = static_cast<Res::ERes>(woodOre[gen->rand.nextInt (0,1)]);
|
||||
obj->ID = Obj::RESOURCE;
|
||||
obj->subID = static_cast<si32>(restype);
|
||||
obj->amount = 0;
|
||||
object = obj;
|
||||
currentValue += 1000;
|
||||
}
|
||||
else if (nextValue >= 750)
|
||||
{
|
||||
auto obj = new CGResource();
|
||||
obj->ID = Obj::RESOURCE;
|
||||
obj->subID = static_cast<si32>(Res::ERes::GOLD);
|
||||
obj->amount = 0;
|
||||
object = obj;
|
||||
currentValue += 750;
|
||||
}
|
||||
else //no possible treasure left (should not happen)
|
||||
break;
|
||||
|
||||
//TODO: generate actual zone and not just all objects on a pile
|
||||
placeObject(gen, object, pos);
|
||||
}
|
||||
if (object)
|
||||
{
|
||||
guardObject (gen, object, currentValue);
|
||||
return true;
|
||||
}
|
||||
else //we did not place eveyrthing successfully
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CRmgTemplateZone::fill(CMapGenerator* gen)
|
||||
{
|
||||
int townId = 0;
|
||||
@ -515,15 +650,14 @@ bool CRmgTemplateZone::fill(CMapGenerator* gen)
|
||||
guardObject (gen, obj.first, obj.second);
|
||||
}
|
||||
}
|
||||
std::vector<CGObjectInstance*> guarded_objects;
|
||||
static auto res_gen = gen->rand.getIntRange(Res::ERes::WOOD, Res::ERes::GOLD);
|
||||
const double res_mindist = 5;
|
||||
do {
|
||||
|
||||
//TODO: just placeholder to chekc for possible locations
|
||||
auto obj = new CGResource();
|
||||
auto restype = static_cast<Res::ERes>(res_gen());
|
||||
obj->ID = Obj::RESOURCE;
|
||||
obj->subID = static_cast<si32>(restype);
|
||||
obj->subID = static_cast<si32>(Res::ERes::GOLD);
|
||||
obj->amount = 0;
|
||||
do {
|
||||
|
||||
int3 pos;
|
||||
if ( ! findPlaceForObject(gen, obj, res_mindist, pos))
|
||||
@ -531,22 +665,10 @@ bool CRmgTemplateZone::fill(CMapGenerator* gen)
|
||||
delete obj;
|
||||
break;
|
||||
}
|
||||
placeObject(gen, obj, pos);
|
||||
createTreasurePile (gen, pos);
|
||||
|
||||
if ((restype != Res::ERes::WOOD) && (restype != Res::ERes::ORE))
|
||||
{
|
||||
guarded_objects.push_back(obj);
|
||||
}
|
||||
} while(true);
|
||||
|
||||
for(const auto &obj : guarded_objects)
|
||||
{
|
||||
if ( ! guardObject(gen, obj, 1000))
|
||||
{
|
||||
//TODO, DEL obj from map
|
||||
}
|
||||
}
|
||||
|
||||
auto sel = gen->editManager->getTerrainSelection();
|
||||
sel.clearSelection();
|
||||
for (auto tile : tileinfo)
|
||||
|
@ -114,6 +114,7 @@ public:
|
||||
|
||||
void addRequiredObject(CGObjectInstance * obj, si32 guardStrength=0);
|
||||
void addMonster(CMapGenerator* gen, int3 &pos, si32 strength);
|
||||
bool createTreasurePile (CMapGenerator* gen, int3 &pos);
|
||||
bool fill(CMapGenerator* gen);
|
||||
void createBorder(CMapGenerator* gen);
|
||||
bool crunchPath (CMapGenerator* gen, const int3 &src, const int3 &dst, TRmgTemplateZoneId zone);
|
||||
|
Loading…
Reference in New Issue
Block a user