Jump to content
Sign in to follow this  
dwringer

Town Construction Set Initialization the Easy Way

Recommended Posts

***UPDATED: 2/12/2011***

'mode' variable now takes up to three positions to the right of the decimal place. Script is MUCH more predictable and configurable; zones can be initialized to guarantee the same building placement as far as has been tested.

Since I was always confounded by the unintuitive process of setting up and debugging a Town Construction Set module every time I wanted to make a certain kind of random town, I figured some of the process could be automated within reasonable constraints to generate reasonably appropriate towns for a variety of situations.

Therefore I came up with, and present to you all, a very rudimentary script to set the initialization variables for Town Construction Set modules with only a single, higher-level line of code within the editor. To do this, make a file called "tginit.sqf" and paste the following code into it:

//////////////////////////////////////
///   Town Generator Initializer   ///
///    Author: Darren Ringer       ///
//////////////////////////////////////////////////////////////////
//								//
// Instructions: place this file     		  		//
//  into your missions folder.       				//
//  Place a Town Construction set    				//
//  module on the map, and in its    				//
//  initialization field, put:       				//
//   								//
//   nul = [this,<mode><.xyz>,<radius>] execVM "tginit.sqf"    //
//    								//
//  Where <mode> is determined as follows:			//
//      0 = sparse buildings					//
//      1 = loose suburban arrangement				//
//      2 = village-like arrangement				//
//	3 = dense, city-like arrangement			//
//   This integer can optionally be followed by up to three     //
//    decimal places (x, y, and z above), as follows:		//
//	x :: if nonzero, scales the number of buildings, so     //
//	      mode 0.5 would make half as many buildings as     //
//            would mode 0.					//
//	y :: if nonzero, specifies a proportion of the number   //
//	      of buildings to be randomized, so mode 2.03 would //
//            generate 70 to 100% as many buildings as mode 2.  //
//	z :: specifies proportion of random deviation from 1.5  //
//	      (the default) as a multiplier to make trash and   //
//	      misc objects based on the total number of 	//
//	      buildings created.				//
//   and  <radius> is simply the maximum distance from		//
//    your Town Construction Set module at which you want	//
//    buildings to be created.					//
//								//
//   NOTE: Certain modes will not work below a certain radius   //
//          size. In these cases, the mode will automatically   //
//          get set to a compatible (denser) mode. No mode has	//
//	    been tested to be effective below a 50m radius.	//
// 								//
//////////////////////////////////////////////////////////////////

// For example,
//  nul = [this, 1.735, 350] execVM "tginit.sqf"
//   in the init field of a Town Construction Modle
//   will create a town of radius 350 with mode 1 (scattered
//   buildings), 70% as many buildings as would normally be 
//   in a mode 1 r 350 zone, 30% of which may or may not
//   exist, and 0.75-2.25x as many misc objects as
//   buildings.

_tcs = _this select 0;
_mode = _this select 1;
_radius = _this select 2;
_size = 2 * _radius;
_miscrand = ((100 * _mode) % 1);
_mode = _mode - (_miscrand * 0.01);
_houserand = ((10 * _mode) % 1);
_mode = _mode - (_houserand * 0.1);
_scalar = (_mode % 1);
_mode = _mode - _scalar;

if (_radius < 100) then {
if (_mode < 3) then {
	_mode = 3;
};
};

if (_radius < 200) then {
if (_mode < 2) then {
	_mode = 2;
};
};

if (_radius < 400) then {
if (_mode < 1) then {
	_mode = 1;
};
};

switch (_mode) do {
case 0: {
	tgdivisor = 90000;
	tgspac = 22;
};
case 1: {
	tgdivisor = 46181;
	tgspac = 7.6;
};
case 2: {
	tgdivisor = 22500;
	tgspac = 4;
};
case 3: {
	tgdivisor = 2400;
	tgspac = 1.3;
};
};

sCoeff = _scalar;
if (_scalar == 0) then {sCoeff = 1;};
_count = (ceil (sCoeff * ((3.14159 * (_radius * _radius)) / tgdivisor)));	


_vals = [   
_size, 
(ceil ((_count - (_count * _houserand)) + (random (_count * _houserand)))),
28, 
tgspac, 
(1.5 - (1.5 * _miscrand) + (3 * _miscrand))
];       
_vars = [   
"townSize",    
"houseCount",    
"houseRotation",    
"houseSpacing",    
"coefMisc"  
];


{_tcs setVariable [_x, (_vals select _forEachIndex)]} forEach _vars;

tgdivisor = nil; tgspac = nil; sCoeff = nil;

Then in the init of each town generator you want to set up with the script, just put:

[this, <mode>, <radius>] execVM "tginit.sqf"

Where <mode> is an int [0-3] defining the density of the buildings (3 being the most dense), and <radius> defines the radius (NOT the "size") of the town. The module's internal variable appears to operate as a diameter and not a radius as indicated by the wiki. My script lets you think in terms of radii. :p

-------------------------------

Feature added 2/12/2011:

Instead of setting mode to a single integer like 2, you can now do something like:

[this, 2.905, 500] execVM "tginit.sqf"

This gets a little tricky, so let me break it down. If mode is represented as A.XYZ,

A :: [0-3] (general zone density, 3 being the densest of the four options)

X :: [0-9] (if zero, does nothing. if 1-9, scales the number of buildings 10% to 90%)

Y :: [0-9] (determines what percentage of the number of buildings in zone may or may not be generated. A 4 here makes between 60% and 100% as many buildings as a 0, for instance. this precludes the zone being generated the same every time.)

Z :: [0-9] (by default, misc objects are created as a quantity 1.5x that of the number of buildings. this num determines what percentage above or below 1.5x will be randomized in the same way houses are randomized by variable Y. a 5 here would use a random coefficient: from 0.75 to 2.22x the number of buildings, for instance.)

Thus, the example above will make a 500 radius zone with mode 2 density, 90% the typical number of buildings in such a zone, zero randomness as far as the number of buildlings, and 50% random deviance from the 1.5x multiplier to create misc objects.

The primary motivation for this change was so that zones will consistently load once you have them set the way you want them (assuming you use a 0 for the tenths place), and if you can't get a zone to load (too many rocks or mountains or something) you can just scale back the number of buildings in it until it WILL load.

-------------------------------

Suggestions, comments, flames, etc are more than welcome.

I understand that a lot of this could be cleaned up, improved, etc. It is very much a work in progress. But I have found it very useful already, and thought it might be of interest to others.

I would like to better understand the spacing variable and its effect, as well as potentially find a more elegant mathematical solution to scaling the different modes. The values right now were obtained through nothing but trial and error, other than the slightly less rational number 46181 that I got by working from a desired number of buildings in a specific size zone (75 in a zone of radius 1050, don't ask, haha).

The randomization elements cause the building placement to be slightly random, if you remove all the randomness you can consistently generate the same zone over and over. That could be handy if you want to populate some of the buildings with some exhausting use of the setpos command.

One thing to keep in mind here is that you can use some very large radii. Mode 0 on a 2400m radius circle sprinkles 200 buildings over a 7 square mile area. That's great for diversifying otherwise empty landscapes, especially maps that don't have many, or any, villages on them.

You can see below (hopefully, despite the terrible image quality thanks to MS Paint), an example of how this can be used. The big zone on the left is density 0; the medium red one is density 2, and the small green ones are density 3. Layering zones like this can cause errors, so you have to be careful with placement. (The colored zones are meaningless markers added for demonstration purposes only)

towns.jpg

Edited by dwringer
Improved code, more features, more reliability, etc.

Share this post


Link to post
Share on other sites

Hi - This is a cool piece of short-cutting for the editor - I am using it for a mission, but I am getting tginit.sqf error messages as the mission loads. An undefinable variable in expression _this (error in line 1) I have uploaded tginit.sqf without without the explanatory notes, greyed out for the cut n paste file in the post :-

_tcs = _this select 0;

_mode = _this select 1;

_radius = _this select ...etc

I can't see how I have missed anything, the error message remains after adding your notes, and also cannot see how the code can be wrong?

Any Pointers?

Foxsch

Share this post


Link to post
Share on other sites

Also noticed that the .sqf is generating town names? Any idea how to null that, so we are left with the name of the town we enter to the description/name fileds in the module? The town has made the 'desert' map a real joy to edit. I'll be putting one together using your suggestion to scatter a town over a few miles radius - excellent : -) Also, it might be a stupid question, but how am I going to enter empty objects, or place units into particular buildings in the set? Scratch that - I found a post that I'll be needing to try out here :- Bohemia Thread but missions with the set in use are occasionally loading twice - once for the Mission, and then again for the Town - I must be missing something critical ...

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
Sign in to follow this  

×