Ok, these are my first attempts at any kind of "real" scripting.
The JTD_cityInit should be run at initialization, or at the beginning of a mission.
Credit goes to OFPEC, hoz, Spooner, and DMarkwick.
First is the JTD City Position function. It gets the general area of a city from the config. As noted, this is almost a direct rip from one of hoz's scripts at OFPEC.
Code: Select all
/* JTD_CityPosition.sqf function.
By Trexian/hoz
The purpose of the JTDCityCenter function is to determine the location of a city area. It is almost
a direct rip of the FindClosestTown function by hoz, available at OFPEC. All I did was change the
elements returned, and tweaked the mechanism for creating the array, as suggested by Spooner.
All credit for this function really goes to hoz.
ooooooooooooooooooooooooooooooooooooooooooooooooooo
No elements passed to it (yet), and it returns the city position from the config.
ooooooooooooooooooooooooooooooooooooooooooooooooooo
Version history
01a - released at OFPEC
01b - fixed pursuant to Spooner's suggestions
- included demo mission
*/
//hint "position init";
//sleep 1;
_towns=[];
_townsTemp = [];
_cfgTowns = (configFile >> "cfgWorlds" >> WorldName >> "Names");
_cfgPath = "";
_return = [];
for [{_z=0}, {_z <count>> "type");
if ((_typecity == "NAMECITY") || (_typecity == "NAMEVILLAGE") || (_typecity == "NAMECITYCAPITAL")) then
{
_return = _return + [[getText (_cfgPath >> "name"),getArray (_cfgPath >> "position")]];
};
};
_return
The second script/function uses a density test to take that position (that is passed to it) and try to find a more central... center.
Code: Select all
/* JTD_CityCenter.sqf function.
By Trexian
ooooooooooooooooooooooooooooooooooooooooooooooooooo
Credits:
OFPEC
DMarkwick, for math
Hoz, for the FindNearestTown resource
Baddo, for findBuildingPositions sqf reference
Raven, for takeBuilding sqs reference
ooooooooooooooooooooooooooooooooooooooooooooooooooo
The purpose of the JTDCityCenter function is to roughly determine the center of a city area.
It starts with the position passed to it (likely the config location of the city), and determines
the densities of the areas in each direction. If one of the densities is larger than the inital,
that becomes the temporary center. The search is repeated until the script reaches a position
that has no higher density in the surrounding area. That position is returned.
ooooooooooooooooooooooooooooooooooooooooooooooooooo
Version history
01a - released at OFPEC
01b - fixed pursuant to Spooner's suggestions
- included demo mission
*/
//hint "center init";
//sleep 1;
_posTown = [0,0];
_cntThis = 0;
_initArray = [];
_initCnt = 0;
_bldgTemp = "";
_bldgPos = 0;
_t = 0;
_z = 0;
_d = 0;
_tempArray = [];
_centerBool = false;
_posCenter = [0,0,0];
_direction = 0;
_cntTemp = 0;
_posTemp = [0,0,0];
_srchPos = [0,0,0];
_srchBldg = [];
_srchArray = [];
_srchCnt = 0;
_holderCnt = 0;
_holderPos = [0,0,0];
_posElem = [];
_posX = 0;
_posY = 0;
_posElem = _this select 0; // position array passed to function
_posX = _posElem select 0;
_posY = _posElem select 1;
_posCenter = [_posX, _posY, 0]; // initial setting of the "center"
_initPos = _posCenter;
_initCnt = 0;
_centerBool = false;
_direction = 0;
while {! _centerBool} do
{
_posTemp = _posCenter;
_holderCnt = _initCnt;
_holderPos = _posCenter;
for [{_d = 1},{_d <= 8},{_d = _d + 1}] do
{
_direction = _direction + 45;
// builds an initial array of buildings within the search area
// the distance could be tweaked, depending on the results
_srchPos = [((_posTemp select 0) + sin (_direction) * 100), ((_posTemp select 1) + cos (_direction) *100), 0];
_tempArray = nearestObjects [_srchPos, ["HOUSE"], 100];
_t = count _tempArray;
_t = _t - 1;
// this is a quick routine to make sure the buildings found are occupiable
for [{_z = 0},{_z <_t> _holderCnt) then
{
_holderPos = _srchPos;
_holderCnt = _srchCnt;
};
// conditional to determine if the search yielded a position different than the last center - that no higher densities were found
if (((_holderPos select 0) != (_posCenter select 0)) && ((_holderPos select 1) != (_posCenter select 1)) && ((_d == 8))) then
{
_posCenter = _holderPos;
_initCnt = _holderCnt;
_d = 0;
};
};
_tempArray = nearestObjects [_holderPos, ["HOUSE"], 50];
if ((count _tempArray) <1> _radA)) then
{
_radA = _dist;
};
if (((_t == 2) || (_t == 4)) && (_dist > _radB)) then
{
_radB = _dist;
};
_radA = _radA * _radiusFactor;
_radB = _radB * _radiusFactor;
_return = [_radA, _radB];
};
_return
Ooops here's the border function.
Code: Select all
/* JTD_CityBorder.sqf function.
By Trexian
The purpose of the JTDCityBorder function is to roughly determine the size of the city being analyzed.
It first determines the baseline density for the center of the city. The analysis is different,
depending on whether it is a high-density or low-density city. The script uses a circle of the given
radius (_radius) to compare the density within the circle to the initial density in each cardinal direction.
When it reaches a certain percentage (_densityCutoff) of the original ratio, it considers that the outer
extent of that direction. The script uses the longer of North/South for the B radius, and East/West for
the A radius. The _radiusFactor is basically something to increase/decrease the size of the radii by an
artificial amount, depending on the needs of the developer. This can also be achieved by altering the
returned elements in the calling script.
Also, within the script, the areas to tweak are:
- the first conditional determines the definition between "big" and "small" cities
- the _dist is the increment for the center of the search
- the _radius determines the size of the circle the search examines to determine the ratio to compare
to the initial ratio
ooooooooooooooooooooooooooooooooooooooooooooooooooo
Credits:
OFPEC
DMarkwick, for math
Hoz, for the FindNearestTown resource
Baddo, for findBuildingPositions sqf reference
Raven, for takeBuilding sqs reference
ooooooooooooooooooooooooooooooooooooooooooooooooooo
Version history
01a - released at OFPEC
01b - fixed pursuant to Spooner's suggestions
- included demo mission
*/
//hint "border init";
//sleep 1;
// these are the main tweakable values
_densityCutoff = .2;
_dist = 0;
_radiusFactor = 0;
_initCnt = 0;
_t = 0;
_d = 0;
_tempArray = [];
_centerBool = false;
_posCenter = [0,0,0];
_direction = 0;
_cntTemp = 0;
_posTemp = [0,0,0];
_srchPos = [0,0,0];
_srchCnt = 0;
_radA = 10;
_radB = 10;
_tmpRatio = .2;
_angle = 0;
_radius = 50;
_posElem = _this select 0;
_return = [];
_posX = _posElem select 0;
_posY = _posElem select 1;
_posCenter = [_posX, _posY, 0];
_tempArray = nearestObjects [_posCenter, ["HOUSE"], 100];
_cntTemp = count _tempArray;
_posCenter = getPos (_tempArray select 0);
_initPos = _posCenter;
_initCnt = _cntTemp;
_initRatio = _cntTemp / 100;
_centerBool = false;
_direction = 0;
// conditional to determine whether to use the Big City function or not
if (_initRatio < .75) then
{
_radius = 100;
_dist = 50;
_densityCutoff = .2;
_radiusFactor = .75;
}
else
{
_radius = 150;
_dist = 50;
_densityCutoff = .1;
_radiusFactor = 1;
};
for [{_t = 1},{_t <4> (_initRatio * _densityCutoff)} do
{
_d = _d + 1;
_dist = _d * _radius;
_direction = _t * 90;
_srchPos = [((_posCenter select 0) + sin (_direction) * (_dist)), ((_posCenter select 1) + cos (_direction) * (_dist)), 0];
_tempArray = nearestObjects [_srchPos, ["HOUSE"], _radius];
_cntTemp = count _tempArray;
_tmpRatio = (_cntTemp / _radius);
};
_d = 0;
// conditional to determine which direction we're looking at
if (((_t == 1) || (_t == 3)) && (_dist > _radA)) then
{
_radA = _dist;
};
if (((_t == 2) || (_t == 4)) && (_dist > _radB)) then
{
_radB = _dist;
};
_radA = _radA * _radiusFactor;
_radB = _radB * _radiusFactor;
_return = [_radA, _radB];
};
_return
An example of how to put this together, this is a script that I reference as an execVM from a init.sqf for a mission. It creates red markers, centered on the returned city center position, with an axis A and axis B that roughly corresponds to the borders of the city.
Code: Select all
/*
JTD City Initialization script
by Trexian
Purpose: run the JTD City functions
Implementation: executed from init or mission.sqm
Future plans will include greater information exchange.
ooooooooooooooooooooooooooooooooooooooooooooooooooo
Version history
01a - released at OFPEC
01b - fixed pursuant to Spooner's suggestions
- included demo mission
ooooooooooooooooooooooooooooooooooooooooooooooooooo
"JTD_CityPosition.sqf"
- passed no parameters
- returns an array of all cities in the config, and the config positions
"JTD_CityCenter.sqf"
- passed a position array (most likely from JTDCityPosition)
- determines the approximate center of the city, by density
- returns the position of the center
"JTD_CityBorder.sqf"
- passed a position array (most likely from JTDCityCenter)
- determines an approximate geographic size of the city in X (radius A) and Y (radius B)
- returns radius A/B for use in marker or trigger
The markers are created to show the scenario developer the location and size of the parameters.
This particular script loads the centers and borders in additional global arrays that are indexed in the
same order as the city list taken from the config.
*/
//hint "city init";
//sleep 1;
_i = 0;
JTD_CityTriggers = [];
JTD_CityCenters = [];
JTD_CityBorders = [];
JTD_cityPos = compile preprocessFileLineNumbers "JTD_CityPosition.sqf";
JTD_cityCent = compile preprocessFileLineNumbers "JTD_CityCenter.sqf";
JTD_cityBord = compile preprocessFileLineNumbers "JTD_CityBorder.sqf";
JTD_citylist = call JTD_cityPos;
_count = (count JTD_citylist) -1;
for [{_i = 0}, {_i <= _count}, {_i = _i + 1}] do
//for [{_i = 0}, {_i < 5}, {_i = _i + 1}] do // for testing, to limit the iterations
{
_citypos = ((JTD_citylist select _i) select 1);
_citycenter = [_citypos] call JTD_cityCent;
_cityborder = [_citycenter] call JTD_cityBord;
_posX = _citycenter select 0;
_posY = _citycenter select 1;
_radA = _cityborder select 0;
_radB = _cityborder select 1;
_trigName = format ["JTDTrig%1", ((JTD_citylist select _i) select 0)];
_JTDTrigMarker = createMarker [_trigName, [_posX, _posY]];
_JTDTrigMarker setMarkerColor "ColorRedAlpha";
_JTDTrigMarker setMarkerShape "ELLIPSE";
_JTDTrigMarker setMarkerSize [_radA, _radB];
// set trigger
_spawnTrig = createTrigger ["EmptyDetector", [_posX, _posY]];
_spawnTrig setTriggerArea [_radA, _radB, 0, true];
_spawnTrig setTriggerActivation ["ANY", "PRESENT", true];
_spawnTrig setTriggerStatements ["this", format ["nul = [%1] execVM 'JTD_DriveFaster.sqf'", _i], ""]; //saves the index to pass to spawn script
JTD_CityTriggers = JTD_CityTriggers + [_trigger]; // Store these variables into global array, so they are indexed to the city list.
JTD_CityCenters = JTD_CityCenters + [_citycenter];
JTD_CityBorders = JTD_CityBorders + [_cityborder];
};
And FINALLY
the "DriveFaster" script referenced in the CityInit and used in the test mission.
Code: Select all
/*
JTD City Functions Proof of Concept script
by Trexian
Purpose: run the JTD City functions
"You dropped a bomb on me, baby,
You dropped a bomb on me."
- Th Gap Band
*/
//hint "init";
//sleep 1;
_index = _this select 0;
_name = (JTD_citylist select _index) select 0;
_cityCenter = JTD_CityCenters select _index;
_cityRadA = (JTD_CityBorders select _index) select 0;
_cityRadB = (JTD_CityBorders select _index) select 1;
_posSpawn = [_cityCenter select 0, _cityCenter select 1, 0];
hint format ["city = %1", _name];
sleep 1;
_randBombs = floor (random ((_cityRadA + _cityRadB) / 5));
// change the 30 to whatever number you want
for [{_q = 0}, {_q <= _randBombs}, {_q = _q + 1}] do
{
_dis = (random 50) + 25;
_dir = random 360;
_x = (_posSpawn select 0) + sin (_dir) * _dis;
_y = (_posSpawn select 1) + cos (_dir) * _dis;
sleep random 5;
_smellslikeLGB = "Bo_GBU12_LGB" createVehicle [_x, _y, 20];
};