Jump to content

Some strange working rmgen lib functions


FeXoR
 Share

Recommended Posts

I noticed that some placers/painters does not work in combination.

- avoidClasses does not seam to work for centered placers.

- SmoothElevationPainter does not seam to work for non-centered placers (at least not properly for a ClumpPlacer of size 1).

- TileClassPainter does not seam to work at all.

Edited by FeXoR
Link to comment
Share on other sites

I noticed that some placers/painters does not work in combination.

- avoidClasses does not seam to work for centered placers.

- SmoothElevationPainter does not seam to work for non-centered placers (at least not properly for a ClumpPlacer of size 1).

- TileClassPainter does not seam to work at all.

Well, according to this, none of the current maps should work.:P

Link to comment
Share on other sites

Well, according to this, none of the current maps should work.:P

OK ^^

Then what do I do wrong when:

var placer = new ClumpPlacer(pathWidth, 1, 1, 1, x, z);
var painter = [new TerrainPainter(terrainPath), new ElevationPainter(-randFloat())];
createArea(placer, painter, avoidClasses(clHill, 20)); // AVOID CLASS DOES NOT WORK!!! Because of centred placer???

Here:

var placer = new ClumpPlacer(1, 1, 1, 1, x, z);
var painter = [new TerrainPainter(terrainWood), new ElevationPainter(randFloat())]; // new TileClassPainter(clForest) RAISES ERROR!!! SmoothElevationPainter(ELEVATION_MODIFY, randFloat(1), 1) STRANGE ACTING!
createArea(placer, painter, avoidClasses(clPath, 2));

If I add SmoothElevationPainter here it's only lowering the terrain when I set elevation AND blendRadius negative.

However, when used with a bigger  ClumpPlacerit seams to work much better though even if the  elevation is positive it sometimes lowers the terrain on the right.

Edited by FeXoR
Link to comment
Share on other sites

OK ^^

Then what do I do wrong when:

var placer = new ClumpPlacer(pathWidth, 1, 1, 1, x, z);
var painter = [new TerrainPainter(terrainPath), new ElevationPainter(-randFloat())];
createArea(placer, painter, avoidClasses(clHill, 20)); // AVOID CLASS DOES NOT WORK!!! Because of centred placer???

First of all, how are you defining x and z?

And second: coherence and smoothness should be floats to ints. use 1.0 instead of 1. I had the same problem before.

pathWidth is not technically correct. Size parameter defines the area of placer not it's width.

But your overall code should work. What do you want to do exactly?

Here:

var placer = new ClumpPlacer(1, 1, 1, 1, x, z);
var painter = [new TerrainPainter(terrainWood), new ElevationPainter(randFloat())]; // new TileClassPainter(clForest) RAISES ERROR!!! SmoothElevationPainter(ELEVATION_MODIFY, randFloat(1), 1) STRANGE ACTING!
createArea(placer, painter, avoidClasses(clPath, 2));

If I add SmoothElevationPainter here it's only lowering the terrain when I set elevation AND blendRadius negative.

However, when used with a bigger ClumpPlacerit seams to work much better though even if the elevation is positive it sometimes lowers the terrain on the right.

I should see your complete code this time. Could you show it to me in PM?

Link to comment
Share on other sites

First of all, how are you defining x and z?

Half the code needed for that so see the full code further below.

And second: coherence and smoothness should be floats to ints. use 1.0 instead of 1. I had the same problem before.

I'll do that but it works for now...

pathWidth is not technically correct. Size parameter defines the area of placer not it's width.

I know:


var pathWidth = 5; // This is not really the path's sickness in tiles but the number of tiles in the clumbs of the path

But your overall code should work.

It does, but the uncommented stuff is the thing in question. So in this code it's the 'avoidClasses' and I have no idea why. I fixed this by painting the hills after the path, so don't tell me that it will not work because no tiles are added to 'clHill' at this point ;) . I just wanted to tell that 'avoidClasses' sometimes fails (maybe because of the centered placer with given coordinated, I don't have a clue)

What do you want to do exactly?

For the dark forest map I want the forest to be placed differently from the other maps to really make it dark (well, at least in theory possible). So I add it on every tile if a random check vs the 'actual density' succeeds. This 'actual density' is mainly the 'maxTreeDensity' (constant for a single map dependent on map size to avoid out of memory errors) scaled by other density modifiers (Dependent on distance to next start location or the center eye candy and the radius to have room to place additional resources at the given radius). This works fine and as I want it.

However, to enable the players to reach the center and each other on more than 1 path I added paths that should cut through the woods (I think that would just be possible by adding the paths after the woods, but I wanted to get used to the painter/placer/constraint/area usage that is in most cases the perfect thing).

I noticed that the paths sometimes run in the non-starting-resource-hills and that looked bad so I added an TileClassPainter(clHill) to the resource area and the avoidClasses(clHill) constraint to the paths. But it didn't avoid the hills. So I placed the hills after the paths.

That was most likely a bug in my code that I didn't find because for the woods (that avoids paths) it works and it's a centered placer, too.

Besides: As it is now only the center of the paths and the resource terrain clumbs are in the corresponding classes not all terrain clumb's tiles.

I should see your complete code this time. Could you show it to me in PM?

Here it is though not in a PM, someone might find it useful (like your suggestion to use float, not int):


RMS.LoadLibrary("rmgen");

// initialize map
log("Initializing map...");
InitMap();


// Setup tile classes
var clPlayer = createTileClass();
var clPath = createTileClass();
var clHill = createTileClass();
var clForest = createTileClass();
// var clWater = createTileClass();
// var clRock = createTileClass();
// var clFood = createTileClass();
// var clBaseResource = createTileClass();

// Setup Templates
var templateStone = "gaia/geology_stone_temperate"
var templateStoneMine = "gaia/geology_stonemine_temperate_quarry";
var templateMetal = "gaia/geology_metal_temperate";
var templateMetalMine = "gaia/geology_metal_temperate_slabs";
var startingResourcees = ["gaia/flora_tree_oak_large", "gaia/flora_bush_temperate", templateStoneMine,
"gaia/flora_bush_grapes", "gaia/flora_tree_apple", "gaia/flora_bush_berry", templateMetalMine, "gaia/flora_bush_temperate"];

// Setup terrain
var terrainWood = ['temp_forestfloor_a|gaia/flora_tree_oak', 'temp_forestfloor_autumn|gaia/flora_tree_carob', 'temp_forestfloor_pine|gaia/flora_tree_pine'];
var terrainWoodBorder = ['temp_grass_plants|gaia/flora_bush_berry', 'temp_grass_clovers_2|gaia/flora_bush_grapes', 'temp_grass_long_b|gaia/flora_tree_apple',
'temp_grass_long|gaia/flora_bush_temperate', 'temp_highlands|gaia/flora_bush_temperate', 'temp_grass_mossy|gaia/flora_bush_temperate',
'temp_grass_plants|gaia/fauna_deer', "temp_mud_plants|gaia/fauna_boar", "temp_grass_long_b|gaia/fauna_rabbit"];
var terrainBase = ['temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b',
'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b',
'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b',
'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b', 'temp_dirt_gravel', 'temp_grass_b',
'temp_grass_b|gaia/fauna_pig', 'temp_dirt_gravel|gaia/fauna_chicken'];
var terrainBaseBorder = ['temp_grass_b', 'temp_grass_b', 'temp_grass_c'];
var terrainPath = ['temp_road', 'temp_grass_b', "temp_road_overgrown"];
var terrainHill = ["temp_highlands", "temp_highlands", "temp_dirt_gravel_b"];
var terrainHillBorder = ["temp_highlands", "temp_mud_plants", "temp_highlands", "temp_mud_plants", "temp_highlands", "temp_mud_plants", "temp_highlands", "temp_mud_plants",
"temp_highlands", "temp_mud_plants", "temp_highlands", "temp_mud_plants", "temp_highlands", "temp_mud_plants", "temp_highlands", "temp_mud_plants",
"temp_grass_clovers_2|gaia/fauna_goat"];


// Setup map
var mapSize = getMapSize();
var mapRadius = mapSize/2;
var playableMapRadius = mapRadius - 5;
var mapCenterX = mapRadius;
var mapCenterZ = mapRadius;

// Setup players and bases
var fortresses = false;
var numPlayers = getNumPlayers();
var baseRadius = 20;
if (fortresses == true)
baseRadius = 30;
var minPlayerRadius = min(mapRadius-1.5*baseRadius, 5*mapRadius/8);
var maxPlayerRadius = min(mapRadius-baseRadius, 3*mapRadius/4);
const BUILDING_ANlE = 3*PI/4;
var buildAngle = 3*PI/4;
var playerStartLocX = new Array(numPlayers);
var playerStartLocZ = new Array(numPlayers);
var playerAngle = new Array(numPlayers);
var playerAngleStart = randFloat(0, 2*PI);
var playerAngleAddAvrg = 2*PI / numPlayers;
var playerAngleMaxOff = playerAngleAddAvrg/4;

// Setup eyecandy
var templateEC = "other/unfinished_greek_temple";
var radiusEC = max(mapRadius/8, baseRadius/2);

// Setup paths
var pathSucsessRadius = baseRadius/2;
var pathAngleOff = PI/2;
var pathWidth = 5; // This is not really the path's sickness in tiles but the number of tiles in the clumbs of the path
if (fortresses == true)
pathSucsessRadius = baseRadius;;

// Setup additional resources
var resourceRadius = 2*mapRadius/3; // 3*mapRadius/8;
var recourcePerPlayer = [];
var resourcePerPlayer = 2;

// Setup woods
var maxTreeDensity = min(256*256/mapSize/mapSize, 1); // Has to be tweeked but works ok
var bushChance = 0.5; // 1 means 50% chance in deepest wood, 0.5 means 25% chance in deepest wood

// Place bases
for (var i=0; i < numPlayers; i++)
{
var civ = g_MapSettings.PlayerData[i].Civ;
var startEntities = getStartingEntities(i);
playerAngle[i] = (playerAngleStart + i*playerAngleAddAvrg + randFloat(0, playerAngleMaxOff))%(2*PI);
var x = round(mapCenterX + randFloat(minPlayerRadius, maxPlayerRadius)*cos(playerAngle[i]));
var z = round(mapCenterZ + randFloat(minPlayerRadius, maxPlayerRadius)*sin(playerAngle[i]));
playerStartLocX[i] = x;
playerStartLocZ[i] = z;
// Place starting entities
createStartingPlayerEntities(x, z, i+1, startEntities, buildAngle)
// Place base texture
var placer = new ClumpPlacer(baseRadius*baseRadius, 1/2, 1/8, 1, x, z);
var painter = [new LayeredPainter([terrainBaseBorder, terrainBase], [2+randFloat()])];
createArea(placer, painter);
addToClass(x, z, clPlayer);
// Place fortresses
if (fortresses == true)
{
// Place fortresses
new wallTool(civ, "small").place(x, z, i+1, buildAngle);
// if (civ == "iber")
// new wallTool("iber").setGenericFortress(x, z, i+1, 20, PI/6);
};
// Place starting resources
var distToSL = 10;
var resStartAngle = playerAngle[i] + PI;
var resAddAngle = 2*PI / startingResourcees.length;
for (var rIndex = 0; rIndex < startingResourcees.length; rIndex++)
{
var angleOff = randFloat(-resAddAngle/2, resAddAngle/2);
var placeX = x + distToSL*cos(resStartAngle + rIndex*resAddAngle + angleOff);
var placeZ = z + distToSL*sin(resStartAngle + rIndex*resAddAngle + angleOff);
placeObject(placeX, placeZ, startingResourcees[rIndex], 0, randFloat(0, 2*PI));
};
};

// Place paths (2 path between each 2 players and each player and the eyecandy in the middle)
for (var i = 0; i < numPlayers+1; i++)
{
for (var j = 0; j < numPlayers+1; j++)
{
if (i < numPlayers)
{
var x = playerStartLocX[i];
var z = playerStartLocZ[i];
}
else
{
var x = mapCenterX;
var z = mapCenterZ;
};
if (j < numPlayers)
{
var targetX = playerStartLocX[j];
var targetZ = playerStartLocZ[j];
}
else
{
var targetX = mapCenterX;
var targetZ = mapCenterZ;
};
var angle = getAngle(x, z, targetX, targetZ);
x += round(pathSucsessRadius*cos(angle));
z += round(pathSucsessRadius*sin(angle));
var targetReached = false;
var tries = 0;
while (targetReached == false && tries < 2*mapSize)
{
var placer = new ClumpPlacer(pathWidth, 1, 1, 1, x, z);
var painter = [new TerrainPainter(terrainPath), new ElevationPainter(-randFloat())];
createArea(placer, painter, avoidClasses(clHill, 20)); // DOES NOT WORK!!! Because of centred placer???
addToClass(x, z, clPath);
// Set vars for next loop
angle = getAngle(x, z, targetX, targetZ);
x += round(cos(angle + randFloat(-pathAngleOff/2, 3*pathAngleOff/2)));
z += round(sin(angle + randFloat(-pathAngleOff/2, 3*pathAngleOff/2)));
if (getDistance(x, z, targetX, targetZ) < pathSucsessRadius)
targetReached = true;
tries++;

};
};
};

// Place expansion resources
for (var i=0; i < numPlayers; i++)
{
for (var rIndex = 0; rIndex < resourcePerPlayer; rIndex++)
{
if (numPlayers > 1)
var angleDist = (playerAngle[(i+1)%numPlayers] - playerAngle[i] + 2*PI)%(2*PI);
else
var angleDist = 2*PI;
var placeX = round(mapCenterX + resourceRadius*cos(playerAngle[i] + (rIndex+1)*angleDist/(resourcePerPlayer+1)));
var placeZ = round(mapCenterX + resourceRadius*sin(playerAngle[i] + (rIndex+1)*angleDist/(resourcePerPlayer+1)));
if (rIndex%2 == 0)
placeObject(placeX, placeZ, templateStone, 0, randFloat(0, 2*PI));
else
placeObject(placeX, placeZ, templateMetalMine, 0, randFloat(0, 2*PI));
var placer = new ClumpPlacer(40, 1/2, 1/8, 1, placeX, placeZ);
var painter = [new LayeredPainter([terrainHillBorder, terrainHill], [1]), new ElevationPainter(1+randFloat())];
createArea(placer, painter);
// addToClass(placeX, placeX, clHill);
};
};

// Place eyecandy
placeObject(mapCenterX, mapCenterZ, templateEC, 0, randFloat(0, 2*PI));
var placer = new ClumpPlacer(radiusEC*radiusEC, 1/2, 1/8, 1, mapCenterX, mapCenterZ);
var painter = [new LayeredPainter([terrainHillBorder, terrainHill], [radiusEC/4]), new ElevationPainter(1+randFloat())];
createArea(placer, painter);
addToClass(mapCenterX, mapCenterZ, clHill);

// Woods and hills
for (var x = 0; x < mapSize; x++)
{
for (var z = 0;z < mapSize;z++)
{
// Some variables
var radius = Math.pow(Math.pow(mapCenterX - x, 2) + Math.pow(mapCenterZ - z, 2), 1/2);
var minDistToSL = mapSize;
for (var i=0; i < numPlayers; i++)
minDistToSL = min(minDistToSL, getDistance(playerStartLocX[i], playerStartLocZ[i], x, z))
// Woods tile based
var tDensFactSL = max(min((minDistToSL - baseRadius) / baseRadius, 1), 0);
var tDensFactRad = abs((resourceRadius - radius) / resourceRadius);
var tDensFactEC = max(min((radius - radiusEC) / radiusEC, 1), 0);
var tDensActual = maxTreeDensity * tDensFactSL * tDensFactRad * tDensFactEC;
if (randFloat() < tDensActual && radius < playableMapRadius)
{
if (tDensActual < bushChance*randFloat()*maxTreeDensity)
{
var placer = new ClumpPlacer(1, 1, 1, 1, x, z);
var painter = [new TerrainPainter(terrainWoodBorder), new ElevationPainter(randFloat())];
createArea(placer, painter, avoidClasses(clPath, 1));
}
else
{
var placer = new ClumpPlacer(1, 1, 1, 1, x, z);
var painter = [new TerrainPainter(terrainWood), new ElevationPainter(randFloat())]; // new TileClassPainter(clForest)
createArea(placer, painter, avoidClasses(clPath, 2));
};
addToClass(x, z, clForest);
};
// Hills
var hVarMiddleHill = mapSize/64 * (1+cos(3*PI/2 * radius/mapRadius));
var hVarHills = 5*(1+sin(x/10)*sin(z/10));
setHeight(x, z, getHeight(x, z) + hVarMiddleHill + hVarHills + 1);
};
};


// Export map data
ExportMap();

And a download: fexor_simple2012-3-22.zip

By the way, NONE of the existing maps use 'TileClassPainter' so I'm quite sure it doesn't work properly.

For SmoothElevationPainter: I can't reproduce this on a simple map (why ever) but just replace line 223 with:

var painter = [new TerrainPainter(terrainWoodBorder), new SmoothElevationPainter(ELEVATION_MODIFY, 0.0, 10.0)];

And play around with the 'ClumpPlacer' and 'SmoothElevationPainter' arguments. Then generate the map and watch the terrain elevation below bushes/wild animals/apple trees (all in 'terrainWoodBorder')

I recommend to generate it with 3 players on a small map. It generates relatively fast then and has enough wood/wood border to play around with the variables and see the results.

Writing a test map... 

Edited by FeXoR
Link to comment
Share on other sites

Really strange. But answer this first: Did you add the hill tiles into clHill? You don't do this right now and this can be the reason avoidClasses didn't work.

I think all of these are caused by your hardcoded map generation. That's why I think you should create your own random map generation library based on some "areas" that have a chance of having trees/special terrain/ etc.

I personally use paintClass() instead of TileClassPainter(). It seems it is buggy. Use paintClass() instead and you may find out that avoidClasses works for the first part.

Link to comment
Share on other sites

Really strange. But answer this first: Did you add the hill tiles into clHill? You don't do this right now and this can be the reason avoidClasses didn't work.

I think all of these are caused by your hardcoded map generation. That's why I think you should create your own random map generation library based on some "areas" that have a chance of having trees/special terrain/ etc.

I personally use paintClass() instead of TileClassPainter(). It seems it is buggy. Use paintClass() instead and you may find out that avoidClasses works for the first part.

@ avoidClasses: Yes, I think that was a bug in my script (though I added the center of the resource clump to clHill with addToClass).

@ own libs: Yes, I may do this. But for now I want to finalize my wall tool (circle and generic fortress allrdy working without rotation yet, 'placeSimple wall' that places a wall of given wall elements from 1 point to another will be added too). Than I will look into the coordinate change that effects the unit placement as well and so has wide effects (see this and following posts). To add placement functionality like in my map I have to look deeper into the code to make it compatible with the existing ones if possible (would be nice).

@ paintClass(): Thx, that might help. Testing though unneeded at the moment.

Some other questions:

1.) What do you mean by 'hard-coded'? Beyond the forest placement (which is IMO unique and might not be generally useful for other maps) and the paths (there need is somehow a consequence of the deep forest) I don't see any hard-coded things. When I'm satisfied think of rewriting them for libs though. Of course the player's start position placement could be generalized for different types of maps but it is done like that in other maps too. If I had access to the SVN repository I would really be more inspired to add library functions and total new libraries than I am now. I don't want to ask someone regularly to add an SVN update! However, Please tell me what other parts belong into libs.

2.) Why are the rmgen libs written in a style that prevents refactoring? If something is a class in many cases there is a function that gives back the class but by reading the function you are not closer to understand what the function does because it just gives back an other class object for example. Then, reading the class's construction code, you are not much closer because it uses another class though the used class is exclusively used by 1 other class (or function). Sometimes it appears to me someone wanted to avoid people  refactoring the code. That might be an issue only appearing to me, though. As I said before the functions available does reflect the needs of a random map API quite well. Sometimes I just want to stir around in their guts and have to find out that the code needed for that is longer, slower, more complex and less readable than hard-coding the functionality in the given map itself.

Edited by FeXoR
Link to comment
Share on other sites

@ avoidClasses: Yes, I think that was a bug in my script (though I added the center of the resource clump to clHill with addToClass).

@ own libs: Yes, I may do this. But for now I want to finalize my wall tool (circle and generic fortress allrdy working without rotation yet, 'placeSimple wall' that places a wall of given wall elements from 1 point to another will be added too). Than I will look into the coordinate change that effects the unit placement as well and so has wide effects (see this and following posts). To add placement functionality like in my map I have to look deeper into the code to make it compatible with the existing ones if possible (would be nice).

@ paintClass(): Thx, that might help. Testing though unneeded at the moment.

Some other questions:

1.) What do you mean by 'hard-coded'? Beyond the forest placement (which is IMO unique and might not be generally useful for other maps) and the paths (there need is somehow a consequence of the deep forest) I don't see any hard-coded things. When I'm satisfied think of rewriting them for libs tough. Of course the player's start position placement could be generalized for different types of maps but it is done like that in other maps too. If I had access to the SVN repository I would really be more inspired to add library functions and total new libraries than I am now. I don't want to ask someone regularly to add an SVN update! However, Please tell me what other parts belong into libs.

2.) Why are the rmgen libs written in a style that prevents refactoring? If something is a class in many cases there is a function that gives back the class but by reading the function you are not closer to understand what the function does because it just gives back an other class object for example. Then, reading the class's construction code, you are not much closer because it uses another class though the used class is exclusively used by 1 other class (or function). Sometimes it appears to me someone wanted to avoid people refactoring the code. That might be an issue only appearing to me, though. As I said before the functions available does reflect the needs of a random map API quite well. Sometimes I just want to stir around in their guts and have to find out that the code needed for that is longer, slower, more complex and less readable than hard-coding the functionality in the given map itself.

1: I mean your hill and forest codes are complex enough to cause strange bugs like these. I use a combination of both rmgen functions and my own codes but I try to write my codes in a way to generate content very similar to rmgen functions in structure so that it doesn't cause such errors. One of the best examples of such a thing is Snowflake Searocks.

But there are two solutions for a problem like the one you have. Completely use rmgen functions (which doesn't have the flexibility and beauty of the current system) or completely use your own hardcoded ones (like what is done in the current Latium map but is very hard and time consuming).

2: The whole code is like that. I tried working on some tickets and found such refactoring very common. In fact it is much worse in the code because it uses functions to send values into main engine (C++ one) and vice verse. For a simple patch like "set trading goods for all selected traders" I had to scan 5 different files until I found two appreciate ones.

Link to comment
Share on other sites

1: I mean your hill and forest codes are complex enough to cause strange bugs like these. I use a combination of both rmgen functions and my own codes but I try to write my codes in a way to generate content very similar to rmgen functions in structure so that it doesn't cause such errors. One of the best examples of such a thing is Snowflake Searocks.

But there are two solutions for a problem like the one you have. Completely use rmgen functions (which doesn't have the flexibility and beauty of the current system) or completely use your own hardcoded ones (like what is done in the current Latium map but is very hard and time consuming).

2: The whole code is like that. I tried working on some tickets and found such refactoring very common. In fact it is much worse in the code because it uses functions to send values into main engine (C++ one) and vice verse. For a simple patch like "set trading goods for all selected traders" I had to scan 5 different files until I found two appreciate ones.

1: Oh, yes, my hills (renamed them to general hight map, I guess that's what you mean). That is not really finalized and could be added to a lib as well if finished. Indeed they cause bugs when changing the order in which paths and hills are placed. May be the reason for the strange acting SmoothElevationPainter. Somehow forgot about them ^^

2: Hm, not so good. Maybe it's worth a clean up mission.

Using paintClass() to add areas to classes works well, by the way.

Edited by FeXoR
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...