Random map generator

According to author this list was reverse-engineered from H3. And since he is HotA programmer this is most likely true - list should match H3. How well that list was balanced is a separate question but it should be OK as base.

Actually we can link all of that to sub ID’s - apart from objects that need special handling (towns, heroes, mines, monoliths, etc) there are quite few objects that have sub ID’s. This is full list of objects that have sub ID’s:

artifact, boat, borderGuard, keymasterTent, cartographer, creatureBank, creatureGeneratorCommon, garrison, monolithOneWayEntrance, monolithOneWayExit, monolithTwoWay, mine, monster, resource, seerHut, town, borderGate, hero

In general I agree. But in some cases having per-map limit makes sense. For example obelisks - VCMI should handle 48+ obelisks but it makes no sense gameplay-wise. Probably we should implement per-map limit but use it only in few cases like this one.

And another property that RMG may need - object function (obstacle, treasure, guard, etc)

Could you please translate this formula:

Special objects, like guards, will be handled separately in engine. Most of what we need for now is one list with treasure objects and the other with obstacles. Another issue is to allow for example new monoliths or new keymaster colors, but this is not urgent.
My recent tests show that RMG treats all the treasures equally.

Sure:

Creature dwelling (separate object for each creature type, 4-slot dwellings will not be generated):
(Creature AI Value)((Creature growth)(1 + (num of zones with home town)/(num of zones with main town)) + (num of zones with home town)/2) - 40
(will be generated only in zones with home town).

*home town - main town that produces this creature.

Should not be a problem - new keymasters/monoliths should be implemented as new subtypes of existing objects. This means that object handler API would need method like “get # of object subtypes”. Will do

Warmonger, can you take a look on this? This is loop that generates map border image:
github.com/vcmi/vcmi/blob/devel … r.cpp#L210

At line 210 that right now looks like this:

else if(j == -1 && i > -1 && i < sizes.y)

I think that this is the typo that causes broken map border on rectangular map. Instead it should check for size.x:

else if(j == -1 && i > -1 && i < sizes.x)

That sounds right, however I never saw that piece of code before :wink:

That formula won’t give less than 400K value for Azure Dragon dwelling on CoD, though they used to spawn with 120K treasure value, too. However, it gives acceptable results for lesser dwellings.
The only way to make it work is to assume that the number of home towns for neutral creatures is always 0. But then the value of dwelling is 78K. But then, Azure Dragon dwelllings tend to spawn alone with value only 78800. Another issue is that the strength of guards can vary for just the same objects.

Reverse-engineering of RMG is not a simple task :stuck_out_tongue:

Forums seems to be down yet again so this is what I found using google cache. Note the very last line - this is likely source of different guards for same objects.

Calculation of guard AI value
zone monsters strength = -1 … 1 (defined in template: none, weak, average or strong)
map monster strength = 2 … 4 (defined before map generation by player)

moster strength = zone strength + map strength (resulting in range 1 … 5)

Then RMG selects values and multipliers according to this table:

moster strength	1     2     3     4     5
value1        	2500  1500  1000  500   0
multiplier1   	0.5   0.75  1.0   1.5   1.5
value2        	7500  7500  7500  5000  5000
multiplier2   	0.5   0.75  1.0   1.0   1.5

strength1 = (treasure value - value1) * multiplier1;
strength2 = (treasure value - value2) * multiplier2;

Guard value = strength1 + strength2

  • If strength1 is negative it won’t be added to guard value

  • If strength2 is negative it won’t be added to guard value

  • If guard value is below 2000 object will not have any guards at all

For zone connection guards calculations are almost identical except for lack of “zone monster strength”. Note that in case of monoliths/subterranean gates guards will be placed on each side of path.

Selection of creatures

Creature is applicable to be used as guard if:
AI Value * (Adv map max + Adv map min) / 2 < Guard value < AI Value * 100

Initial size of guard stack is:
Preferred size = Guard value / AI value

if (preferred size < 4)
size = preferred size
else
size = rand(0.75, 1.25) * preferred size

Fun part is that I remember post from Sav (same author as everything else here) that placement of neutral dwellings in town-free zones is an obvious bug in RMG :slight_smile:

To summarize RMG <-> objects relation. I’m going to provide access to following info:

As part of object handler:

std::set<si32> knownObjects();
std::set<si32> knownSubobjects(si32 primaryID);

As part of object type:

  1. Test for static decorations
  2. For treasures-only - struct that looks like this:
struct RandomMapInfo
{
    ui32 value;
    ui32 perZoneLimit;
    ui32 perMapLimit;
    ui32 rarity; // better name?
}

If value is 0 - then object can not be placed by RMG or have special rules (decorations, towns, etc)

Is that OK? Anything else?

Looks good. However, I ran into more serious issues:

  • Generating objects on RMG side duplicates MapFormatH3M.cpp functionality. Some object factory would be nice, as now constructor of each object class needs to be called separately.
  • I see a need for clone pattern as well to clone existing objects and still hold the info about their properties. Keep in mind that still not all the objects can be easily cloned, for example CArtifact hold pointer to CArtifactInstance in CMap object.
  • Many objects, like a ton of Pandora Box variations, don’t fit in simple config files. They probably need to be hardcoded.

Basically what I want to do is to generate collection of preconfigured object instances and then just draw random objects from it, clone them and place on a map.

That’s one of reasons why I started all of this - all that huge code we had in RMG just to properly generate one town - this has to be encapsulated somewhere. I already have such factory-like objects but writing proper factory for each object will take time. Perhaps I’ll try to stabilize my branch ASAP and then merge it into develop so object-specific factories can be finished in parallel with other tasks.

I’m not sure if properly functional cloning can be achieved easily - I’m more in favor of using templates to create correctly configured objects. Another issue is that I want to blackbox objects as much as possible - RMG should not be responsible for configuring objects.

Hmmm… except for objects like Pandoras (same ID+subID but different “state” and RMG value) my current approach should be OK.

Easiest approach would be to create separate subobject (with own subID) for each of these cases - so we’ll have subID 0 for pandoras from H3 maps, subID 1 for pandoras with 5k exp for RMG, subID 2 for 10k exp and so on. Don’t like this approach much - will try to find better way to handle this.

I just try to wrap all the object constructors + setup in lambdas. This will allow us to configure arbitrary properties of every object, hopefully can be generated from config for typical objects and seems lightweight. Also, no dangling pointers, cloning and such.

Progress report.

i118.photobucket.com/albums/o102/DjFaust/VCMI/RMG06_zpsa333b414.png

Just idea. We already have typeinfo-based factory for boost`s serialization. Can we reuse it for map loading/RMG?

I don’t think so. What we need is an easy way to create multiple similar objects.

Serializer knows about all possible map objects but it can’t configure them - it can only create empty object and then initalize it from binary file or from another object. But this another object must be configured somehow to begin with.

This configuration information should be loaded either in constructor or in some factory method. I don’t think that placing this info in constructor is a good idea since one class usually represent multiple objects - this will result in endless switches we have in objects code right now.

This leaves factory - pretty much approach that I have taken. Set of object-specific factories that load json configuration for object handled by them.

I’ve got an idea on how to place non-removable objects as well as large objects in piles, but to realize it, I’d need info about object shape (template?) before any object is actually created. Probably will hold on with that part until objects branch is merged.

Added info about towns & mines, now you can actually tell the template from the picture :stuck_out_tongue:

i118.photobucket.com/albums/o102/DjFaust/VCMI/RMG07_zpsb6e374b8.png

Added random obstacles.

i118.photobucket.com/albums/o102/DjFaust/VCMI/RMG08_zps14e7da89.png

Still, WoG objects have odd blockmaps and can spawn on any terrain, it seems :confused:

Nice, too bad it generates now single-tiled not multi-tiled objects, but iI guess it it still in development :slight_smile:

Wow. that looks like a huge improvement over what we had before.

As for wog objects - one possibility is that we’re using wrong file to load objects - IIRC wog has 3 files with object lists. You can change used one in wogFileOverrides.json file.

And if that won’t help - we can redefine wog objects and give them proper blockmaps/allowed terrains.

Beegee, what are possible formats for map size in random map template?

The template format allows to specify the sizes with one of these codes: s (36x36), m (72x72), l (108x108) and xl (144x144). With +u (e.g. s+u) you can say that maps with underground are possible as well. Alternatively you can also specify template size in that format: 120x120x1 -> 120 width, 120 height, 1=underground. 0 is for overground.

Template sizes specify only min/max sizes which are allowed. To generate maps with “special” sizes you need to set size properties in CMapGenOptions. Via GUI you only have the possibility to select S, M, L or XL and that determines generated map size.

IMO we should improve map generation properties screen in the long run. But that’s another discussion.

BTW, is there any wiki page about RMG/template format? (perhaps we could collect a few infos there)