diff --git a/client/CPreGame.cpp b/client/CPreGame.cpp index 3eb999988..e032d8d9c 100644 --- a/client/CPreGame.cpp +++ b/client/CPreGame.cpp @@ -1709,7 +1709,7 @@ CRandomMapTab::CRandomMapTab() addButtonsWithRandToGroup(monsterStrengthGroup, monsterStrengthBtns, 0, 2, WIDE_BTN_WIDTH, 248, 251); monsterStrengthGroup->onChange = [&](int btnId) { - mapGenOptions.setMonsterStrength(static_cast(btnId)); + mapGenOptions.setMonsterStrength(static_cast(btnId + EMonsterStrength::GLOBAL_WEAK)); //value 2 to 4 }; // Show random maps btn diff --git a/config/rmg.json b/config/rmg.json index 99e318f85..f51522b06 100644 --- a/config/rmg.json +++ b/config/rmg.json @@ -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 }, diff --git a/lib/rmg/CMapGenOptions.cpp b/lib/rmg/CMapGenOptions.cpp index cf3db66e1..c1f26e443 100644 --- a/lib/rmg/CMapGenOptions.cpp +++ b/lib/rmg/CMapGenOptions.cpp @@ -216,11 +216,11 @@ void CMapGenOptions::finalize(CRandomGenerator & rand) if(waterContent == EWaterContent::RANDOM) { - waterContent = static_cast(rand.nextInt(EWaterContent::LAST_ITEM)); + waterContent = static_cast(rand.nextInt(EWaterContent::NONE, EWaterContent::ISLANDS)); } if(monsterStrength == EMonsterStrength::RANDOM) { - monsterStrength = static_cast(rand.nextInt(EMonsterStrength::LAST_ITEM)); + monsterStrength = static_cast(rand.nextInt(EMonsterStrength::GLOBAL_WEAK, EMonsterStrength::GLOBAL_STRONG)); } //rectangular maps are the future of gaming diff --git a/lib/rmg/CMapGenOptions.h b/lib/rmg/CMapGenOptions.h index 6757ac436..4829fa00d 100644 --- a/lib/rmg/CMapGenOptions.h +++ b/lib/rmg/CMapGenOptions.h @@ -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 }; } diff --git a/lib/rmg/CMapGenerator.cpp b/lib/rmg/CMapGenerator.cpp index 4e51b3e6e..57827e96f 100644 --- a/lib/rmg/CMapGenerator.cpp +++ b/lib/rmg/CMapGenerator.cpp @@ -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 diff --git a/lib/rmg/CRmgTemplateZone.cpp b/lib/rmg/CRmgTemplateZone.cpp index 8cd64482c..7cfd2a360 100644 --- a/lib/rmg/CRmgTemplateZone.cpp +++ b/lib/rmg/CRmgTemplateZone.cpp @@ -403,15 +403,37 @@ 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(); @@ -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(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(restype); + obj->amount = 0; + object = obj; + currentValue += 1400; + } + else if (nextValue >= 1000) + { + auto obj = new CGResource(); + auto restype = static_cast(woodOre[gen->rand.nextInt (0,1)]); + obj->ID = Obj::RESOURCE; + obj->subID = static_cast(restype); + obj->amount = 0; + object = obj; + currentValue += 1000; + } + else if (nextValue >= 750) + { + auto obj = new CGResource(); + obj->ID = Obj::RESOURCE; + obj->subID = static_cast(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 guarded_objects; - static auto res_gen = gen->rand.getIntRange(Res::ERes::WOOD, Res::ERes::GOLD); const double res_mindist = 5; + + //TODO: just placeholder to chekc for possible locations + auto obj = new CGResource(); + obj->ID = Obj::RESOURCE; + obj->subID = static_cast(Res::ERes::GOLD); + obj->amount = 0; do { - auto obj = new CGResource(); - auto restype = static_cast(res_gen()); - obj->ID = Obj::RESOURCE; - obj->subID = static_cast(restype); - obj->amount = 0; 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) diff --git a/lib/rmg/CRmgTemplateZone.h b/lib/rmg/CRmgTemplateZone.h index 1c5970de8..754264063 100644 --- a/lib/rmg/CRmgTemplateZone.h +++ b/lib/rmg/CRmgTemplateZone.h @@ -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);