1
0
forked from 0ad/0ad

Simplifies random map output, see #782.

Changes random maps to XZ coordinates, matching the engine.
More documentation for rmgen library.

This was SVN commit r9271.
This commit is contained in:
historic_bruno 2011-04-16 04:04:06 +00:00
parent 3adba8721a
commit b4503bb61e
30 changed files with 623 additions and 425 deletions

View File

@ -2,7 +2,7 @@
// Constants
// TODO: Move some of these into common location (other scripts may need)
const MAP_SIZES_TEXT = ["Tiny (2 player)", "Small (3 player)", "Medium (4 player)", "Normal (6 player)", "Large (8 player)", "Very Large", "Giant"];
const MAP_SIZES_DATA = [8, 12, 16, 20, 24, 28, 32];
const MAP_SIZES_DATA = [128, 192, 256, 320, 384, 448, 512];
// Max number of players for any map
const MAX_PLAYERS = 8;
@ -28,7 +28,7 @@ var g_GameAttributes = {
map: "",
mapPath: "",
settings: {
Size: 12,
Size: 192,
Seed: 0,
BaseTerrain: "grass1_spring",
BaseHeight: 0,

View File

@ -60,7 +60,7 @@ var clSettlement = createTileClass();
// place players
var playerX = new Array(numPlayers+1);
var playerY = new Array(numPlayers+1);
var playerZ = new Array(numPlayers+1);
var playerAngle = new Array(numPlayers+1);
var startAngle = randFloat() * 2 * PI;
@ -68,7 +68,7 @@ for (var i=1; i<=numPlayers; i++)
{
playerAngle[i] = startAngle + i*2*PI/numPlayers;
playerX[i] = 0.5 + 0.35*cos(playerAngle[i]);
playerY[i] = 0.5 + 0.35*sin(playerAngle[i]);
playerZ[i] = 0.5 + 0.35*sin(playerAngle[i]);
}
for (var i=1; i<=numPlayers; i++)
@ -82,15 +82,15 @@ for (var i=1; i<=numPlayers; i++)
// get the x and y in tiles
var fx = fractionToTiles(playerX[i]);
var fy = fractionToTiles(playerY[i]);
var fz = fractionToTiles(playerZ[i]);
var ix = round(fx);
var iy = round(fy);
var iz = round(fz);
// calculate size based on the radius
var size = PI * radius * radius;
// create the hill
var placer = new ClumpPlacer(size, 0.95, 0.6, 0, ix, iy);
var placer = new ClumpPlacer(size, 0.95, 0.6, 0, ix, iz);
var terrainPainter = new LayeredPainter(
[tCliff, tGrass], // terrains
[cliffRadius] // widths
@ -106,16 +106,16 @@ for (var i=1; i<=numPlayers; i++)
var rampAngle = playerAngle[i] + PI + (2*randFloat()-1)*PI/8;
var rampDist = radius;
var rampX = round(fx + rampDist * cos(rampAngle));
var rampY = round(fy + rampDist * sin(rampAngle));
placer = new ClumpPlacer(100, 0.9, 0.5, 0, rampX, rampY);
var rampZ = round(fz + rampDist * sin(rampAngle));
placer = new ClumpPlacer(100, 0.9, 0.5, 0, rampX, rampZ);
var painter = new SmoothElevationPainter(ELEVATION_SET, elevation-6, 5);
createArea(placer, painter, null);
placer = new ClumpPlacer(75, 0.9, 0.5, 0, rampX, rampY);
placer = new ClumpPlacer(75, 0.9, 0.5, 0, rampX, rampZ);
painter = new TerrainPainter(tGrass);
createArea(placer, painter, null);
// create the central dirt patch
placer = new ClumpPlacer(PI*3.5*3.5, 0.3, 0.1, 0, ix, iy);
placer = new ClumpPlacer(PI*3.5*3.5, 0.3, 0.1, 0, ix, iz);
painter = new LayeredPainter(
[tGrassDirt75, tGrassDirt50, tGrassDirt25, tDirt], // terrains
[1,1,1] // widths
@ -126,7 +126,7 @@ for (var i=1; i<=numPlayers; i++)
var civ = getCivCode(i - 1);
var group = new SimpleGroup( // elements (type, min/max count, min/max distance)
[new SimpleObject("structures/"+civ+"_civil_centre", 1,1, 0,0), new SimpleObject("units/"+civ+"_support_female_citizen", 3,3, 5,5)],
true, null, ix, iy
true, null, ix, iz
);
createObjectGroup(group, i);
@ -134,10 +134,10 @@ for (var i=1; i<=numPlayers; i++)
var bbAngle = randFloat()*2*PI;
var bbDist = 9;
var bbX = round(fx + bbDist * cos(bbAngle));
var bbY = round(fy + bbDist * sin(bbAngle));
var bbZ = round(fz + bbDist * sin(bbAngle));
group = new SimpleGroup(
[new SimpleObject(oBerryBush, 5,5, 0,2)],
true, clBaseResource, bbX, bbY
true, clBaseResource, bbX, bbZ
);
createObjectGroup(group, 0);
@ -149,18 +149,18 @@ for (var i=1; i<=numPlayers; i++)
}
var mDist = 9;
var mX = round(fx + mDist * cos(mAngle));
var mY = round(fy + mDist * sin(mAngle));
var mZ = round(fz + mDist * sin(mAngle));
group = new SimpleGroup(
[new SimpleObject(oStone, 2,2, 0,3),
new SimpleObject(oMetal, 2,2, 0,3)],
true, clBaseResource, mX, mY
true, clBaseResource, mX, mZ
);
createObjectGroup(group, 0);
// create starting straggler trees
group = new SimpleGroup(
[new SimpleObject(oTree, 3,3, 8,12)],
true, clBaseResource, ix, iy
true, clBaseResource, ix, iz
);
createObjectGroup(group, 0, avoidClasses(clBaseResource,2));
@ -170,10 +170,10 @@ for (var i=1; i<=numPlayers; i++)
var gAngle = randFloat()*2*PI;
var gDist = 6 + randInt(9);
var gX = round(fx + gDist * cos(gAngle));
var gY = round(fy + gDist * sin(gAngle));
var gZ = round(fz + gDist * sin(gAngle));
group = new SimpleGroup(
[new SimpleObject(aGrassShort, 3,6, 0,1, -PI/8,PI/8)],
false, clBaseResource, gX, gY
false, clBaseResource, gX, gZ
);
createObjectGroup(group, undefined);
}

View File

@ -90,18 +90,18 @@ var clSettlement = createTileClass();
log("Placing players...");
var playerX = new Array(numPlayers+1);
var playerY = new Array(numPlayers+1);
var playerZ = new Array(numPlayers+1);
var numLeftPlayers = ceil(numPlayers/2);
for (var i=1; i <= numLeftPlayers; i++)
{
playerX[i] = 0.28 + (2*randFloat()-1)*0.01;
playerY[i] = (0.5+i-1)/numLeftPlayers + (2*randFloat()-1)*0.01;
playerZ[i] = (0.5+i-1)/numLeftPlayers + (2*randFloat()-1)*0.01;
}
for (var i=numLeftPlayers+1; i <= numPlayers; i++)
{
playerX[i] = 0.72 + (2*randFloat()-1)*0.01;
playerY[i] = (0.5+i-numLeftPlayers-1)/numLeftPlayers + (2*randFloat()-1)*0.01;
playerZ[i] = (0.5+i-numLeftPlayers-1)/numLeftPlayers + (2*randFloat()-1)*0.01;
}
for (var i=1; i <= numPlayers; i++)
@ -110,16 +110,16 @@ for (var i=1; i <= numPlayers; i++)
// get fractional locations in tiles
var ix = round(fractionToTiles(playerX[i]));
var iy = round(fractionToTiles(playerY[i]));
addToClass(ix, iy, clPlayer);
var iz = round(fractionToTiles(playerZ[i]));
addToClass(ix, iz, clPlayer);
// create TC and starting units
// TODO: Get civ specific starting units
var civ = getCivCode(i - 1);
placeObject(ix, iy, "structures/"+civ + "_civil_centre", i, PI*3/4);
placeObject(ix, iz, "structures/"+civ + "_civil_centre", i, PI*3/4);
var group = new SimpleGroup(
[new SimpleObject("units/"+civ+"_support_female_citizen", 3,3, 5,5)],
true, null, ix, iy
true, null, ix, iz
);
createObjectGroup(group, i);
@ -127,10 +127,10 @@ for (var i=1; i <= numPlayers; i++)
var bbAngle = randFloat()*2*PI;
var bbDist = 9;
var bbX = round(ix + bbDist * cos(bbAngle));
var bbY = round(iy + bbDist * sin(bbAngle));
var bbZ = round(iz + bbDist * sin(bbAngle));
group = new SimpleGroup(
[new SimpleObject(oBerryBush, 5,5, 0,2)],
true, clBaseResource, bbX, bbY
true, clBaseResource, bbX, bbZ
);
createObjectGroup(group, 0);
@ -141,44 +141,50 @@ for (var i=1; i <= numPlayers; i++)
}
var mDist = 9;
var mX = round(ix + mDist * cos(mAngle));
var mY = round(iy + mDist * sin(mAngle));
var mZ = round(iz + mDist * sin(mAngle));
group = new SimpleGroup(
[new SimpleObject(oStone, 2,2, 0,3),
new SimpleObject(oMetal, 2,2, 0,3)],
true, clBaseResource, mX, mY
true, clBaseResource, mX, mZ
);
createObjectGroup(group, 0);
// create starting straggler trees
group = new SimpleGroup(
[new SimpleObject(oPalm, 3,3, 7,10)],
true, clBaseResource, ix, iy
true, clBaseResource, ix, iz
);
createObjectGroup(group, 0, avoidClasses(clBaseResource,2));
}
function distanceToPlayers(x, y)
function distanceToPlayers(x, z)
{
var r = 10000;
for (var i=1; i <= numPlayers; i++)
{
var dx = x - playerX[i];
var dy = y - playerY[i];
r = min(r, dx*dx + dy*dy);
var dz = z - playerZ[i];
r = min(r, dx*dx + dz*dz);
}
return sqrt(r);
}
function playerNearness(x, y)
function playerNearness(x, z)
{
var d = fractionToTiles(distanceToPlayers(x,y));
var d = fractionToTiles(distanceToPlayers(x,z));
if (d < 13)
{
return 0;
}
else if (d < 19)
{
return (d-13)/(19-13);
}
else
{
return 1;
}
}
// Paint elevation
@ -198,11 +204,11 @@ var noise5 = new Noise2D(11 * mapSize/128);
for (var ix=0; ix<=mapSize; ix++)
{
for (var iy=0; iy<=mapSize; iy++)
for (var iz=0; iz<=mapSize; iz++)
{
var x = ix / (mapSize + 1.0);
var y = iy / (mapSize + 1.0);
var pn = playerNearness(x, y);
var z = iz / (mapSize + 1.0);
var pn = playerNearness(x, z);
var h = 0;
var distToWater = 0;
@ -226,7 +232,7 @@ for (var ix=0; ix<=mapSize; ix++)
}
// add some base noise
var baseNoise = 16*noise0.get(x,y) + 8*noise1.get(x,y) + 4*noise2.get(x,y) - (16+8+4)/2;
var baseNoise = 16*noise0.get(x,z) + 8*noise1.get(x,z) + 4*noise2.get(x,z) - (16+8+4)/2;
if ( baseNoise < 0 )
{
baseNoise *= pn;
@ -238,13 +244,13 @@ for (var ix=0; ix<=mapSize; ix++)
// add some higher-frequency noise on land
if ( oldH > 0 )
{
h += (0.4*noise2a.get(x,y) + 0.2*noise2b.get(x,y)) * min(oldH/10.0, 1.0);
h += (0.4*noise2a.get(x,z) + 0.2*noise2b.get(x,z)) * min(oldH/10.0, 1.0);
}
// create cliff noise
if ( h > -10 )
{
var cliffNoise = (noise3.get(x,y) + 0.5*noise4.get(x,y)) / 1.5;
var cliffNoise = (noise3.get(x,z) + 0.5*noise4.get(x,z)) / 1.5;
if (h < 1)
{
var u = 1 - 0.3*((h-1)/-10);
@ -254,7 +260,7 @@ for (var ix=0; ix<=mapSize; ix++)
if (cliffNoise > 0.6)
{
var u = 0.8 * (cliffNoise - 0.6);
cliffNoise += u * noise5.get(x,y);
cliffNoise += u * noise5.get(x,z);
cliffNoise /= (1 + u);
}
cliffNoise -= 0.59;
@ -266,7 +272,7 @@ for (var ix=0; ix<=mapSize; ix++)
}
// set the height
setHeight(ix, iy, h);
setHeight(ix, iz, h);
}
}
@ -284,17 +290,17 @@ var noise10 = new Noise2D(50 * mapSize/128);
for (var ix=0; ix<mapSize; ix++)
{
for (var iy=0; iy<mapSize; iy++)
for (var iz=0; iz<mapSize; iz++)
{
var x = ix / (mapSize + 1.0);
var y = iy / (mapSize + 1.0);
var pn = playerNearness(x, y);
var z = iz / (mapSize + 1.0);
var pn = playerNearness(x, z);
// get heights of surrounding vertices
var h00 = getHeight(ix, iy);
var h01 = getHeight(ix, iy+1);
var h10 = getHeight(ix+1, iy);
var h11 = getHeight(ix+1, iy+1);
var h00 = getHeight(ix, iz);
var h01 = getHeight(ix, iz+1);
var h10 = getHeight(ix+1, iz);
var h11 = getHeight(ix+1, iz+1);
// find min and max height
var maxH = Math.max(h00, h01, h10, h11);
@ -305,12 +311,12 @@ for (var ix=0; ix<mapSize; ix++)
if (maxH > 15)
{
var maxNx = min(ix+2, mapSize);
var maxNy = min(iy+2, mapSize);
var maxNz = min(iz+2, mapSize);
for (var nx=max(ix-1, 0); nx <= maxNx; nx++)
{
for (var ny=max(iy-1, 0); ny <= maxNy; ny++)
for (var nz=max(iz-1, 0); nz <= maxNz; nz++)
{
minAdjHeight = min(minAdjHeight, getHeight(nx, ny));
minAdjHeight = min(minAdjHeight, getHeight(nx, nz));
}
}
}
@ -350,14 +356,14 @@ for (var ix=0; ix<mapSize; ix++)
if (minH < 0)
{
addToClass(ix, iy, clWater);
addToClass(ix, iz, clWater);
}
// cliffs
if (maxH - minH > 2.9 && minH > -7)
{
t = tCliff;
addToClass(ix, iy, clCliff);
addToClass(ix, iz, clCliff);
}
else if ((maxH - minH > 2.5 && minH > -5) || (maxH-minAdjHeight > 2.9 && minH > 0) )
{
@ -368,20 +374,20 @@ for (var ix=0; ix<mapSize; ix++)
else
t = [tDirtCliff, tGrassCliff, tGrassCliff, tGrassRock, tCliff];
addToClass(ix, iy, clCliff);
addToClass(ix, iz, clCliff);
}
// forests
if (maxH - minH < 1 && minH > 1)
{
var forestNoise = (noise6.get(x,y) + 0.5*noise7.get(x,y)) / 1.5 * pn;
var forestNoise = (noise6.get(x,z) + 0.5*noise7.get(x,z)) / 1.5 * pn;
forestNoise -= 0.59;
if (forestNoise > 0)
{
if (minH > 5)
{
var typeNoise = noise10.get(x,y);
var typeNoise = noise10.get(x,z);
if (typeNoise < 0.43 && forestNoise < 0.05)
t = tPoplarForest;
@ -390,12 +396,12 @@ for (var ix=0; ix<mapSize; ix++)
else
t = tPineForest;
addToClass(ix, iy, clForest);
addToClass(ix, iz, clForest);
}
else if (minH < 3)
{
t = tPalmForest;
addToClass(ix, iy, clForest);
addToClass(ix, iz, clForest);
}
}
}
@ -403,7 +409,7 @@ for (var ix=0; ix<mapSize; ix++)
// grass variations
if (t == tGrass)
{
var grassNoise = (noise8.get(x,y) + 0.6*noise9.get(x,y)) / 1.6;
var grassNoise = (noise8.get(x,z) + 0.6*noise9.get(x,z)) / 1.6;
if (grassNoise < 0.3)
{
t = (maxH - minH > 1.2) ? tDirtCliff : tDirt;
@ -413,7 +419,7 @@ for (var ix=0; ix<mapSize; ix++)
t = (maxH - minH > 1.2) ? tGrassCliff : tGrassDry;
if (maxH - minH < 0.5 && randFloat() < 0.03)
{
placeObject(ix+randFloat(), iy+randFloat(), aGrassDry, 0, randFloat()*2*PI);
placeObject(ix+randFloat(), iz+randFloat(), aGrassDry, 0, randFloat()*2*PI);
}
}
else if (grassNoise > 0.61)
@ -424,12 +430,12 @@ for (var ix=0; ix<mapSize; ix++)
{
if ((maxH - minH) < 0.5 && randFloat() < 0.05)
{
placeObject(ix+randFloat(), iy+randFloat(), aGrass, 0, randFloat()*2*PI);
placeObject(ix+randFloat(), iz+randFloat(), aGrass, 0, randFloat()*2*PI);
}
}
}
placeTerrain(ix, iy, t);
placeTerrain(ix, iz, t);
}
}

View File

@ -76,19 +76,19 @@ for (var i=0; i < numPlayers; i++)
// get the x and y in tiles
var fx = fractionToTiles(playerX[i]);
var fy = fractionToTiles(playerY[i]);
var fz = fractionToTiles(playerY[i]);
var ix = round(fx);
var iy = round(fy);
var iz = round(fz);
// calculate size based on the radius
var size = PI * radius * radius;
// create the player area
var placer = new ClumpPlacer(size, 0.9, 0.5, 0, ix, iy);
var placer = new ClumpPlacer(size, 0.9, 0.5, 0, ix, iz);
createArea(placer, paintClass(clPlayer), null);
// create the central road patch
placer = new ClumpPlacer(PI*2*2, 0.6, 0.3, 0.5, ix, iy);
placer = new ClumpPlacer(PI*2*2, 0.6, 0.3, 0.5, ix, iz);
var painter = new TerrainPainter(tDirt);
createArea(placer, painter, null);
@ -99,7 +99,7 @@ for (var i=0; i < numPlayers; i++)
new SimpleObject("structures/"+civ+"_civil_centre", 1,1, 0,0),
new SimpleObject("units/"+civ+"_support_female_citizen", 3,3, 5,5)
],
true, null, ix, iy
true, null, ix, iz
);
createObjectGroup(group, i+1);
@ -107,7 +107,7 @@ for (var i=0; i < numPlayers; i++)
var bbAngle = randFloat()*2*PI;
var bbDist = 10;
var bbX = round(fx + bbDist * cos(bbAngle));
var bbY = round(fy + bbDist * sin(bbAngle));
var bbY = round(fz + bbDist * sin(bbAngle));
group = new SimpleGroup(
[new SimpleObject(oSheep, 5,5, 0,2)],
true, clBaseResource, bbX, bbY
@ -121,18 +121,18 @@ for (var i=0; i < numPlayers; i++)
}
var mDist = 12;
var mX = round(fx + mDist * cos(mAngle));
var mY = round(fy + mDist * sin(mAngle));
var mZ = round(fz + mDist * sin(mAngle));
group = new SimpleGroup(
[new SimpleObject(oStone, 2,2, 0,3),
new SimpleObject(oMetal, 2,2, 0,3)],
true, clBaseResource, mX, mY
true, clBaseResource, mX, mZ
);
createObjectGroup(group, 0);
// create starting straggler trees
group = new SimpleGroup(
[new SimpleObject(oTree, 2,2, 6,12)],
true, null, ix, iy
true, null, ix, iz
);
createObjectGroup(group, 0, avoidClasses(clBaseResource,1));
}

View File

@ -1,4 +1,19 @@
function Area(points)
///////////////////////////////////////////////////////////////////////////
// Area
//
// Object representing a group of points/tiles
//
// points: Array of Point objects
//
///////////////////////////////////////////////////////////////////////////
function Area(points, id)
{
this.points = (points !== undefined ? points : []);
this.id = id;
}
Area.prototype.getID = function()
{
return this.id;
}

View File

@ -1,27 +1,37 @@
///////////////////////////////////////////////////////////////////////////
// NullConstraints: No constraint - always return true
// NullConstraint
//
// Class representing null constraint - always valid
//
///////////////////////////////////////////////////////////////////////////
function NullConstraint() {}
NullConstraint.prototype.allows = function(x, y)
NullConstraint.prototype.allows = function(x, z)
{
return true;
};
///////////////////////////////////////////////////////////////////////////
// AndConstraints: Check multiple constraints
// AndConstraint
//
// Class representing a logical AND constraint
//
// constraints: Array of contraint objects, all of which must be satisfied
//
///////////////////////////////////////////////////////////////////////////
function AndConstraint(constraints)
{
this.constraints = constraints;
}
AndConstraint.prototype.allows = function(x, y)
AndConstraint.prototype.allows = function(x, z)
{
for (var i=0; i < this.constraints.length; ++i)
{
if (!this.constraints[i].allows(x, y))
if (!this.constraints[i].allows(x, z))
return false;
}
@ -30,32 +40,48 @@ AndConstraint.prototype.allows = function(x, y)
///////////////////////////////////////////////////////////////////////////
// AvoidAreaConstraint
//
// Class representing avoid area constraint
//
// area: Area object, containing points to be avoided
//
///////////////////////////////////////////////////////////////////////////
function AvoidAreaConstraint(area)
{
this.area = area;
}
AvoidAreaConstraint.prototype.allows = function(x, y)
AvoidAreaConstraint.prototype.allows = function(x, z)
{
return g_Map.area[x][y] != this.area;
return g_Map.area[x][z] != this.area.getID();
};
///////////////////////////////////////////////////////////////////////////
// AvoidTextureConstraint
//
// Class representing avoid texture constraint
//
// textureID: ID of the texture to be avoided
//
///////////////////////////////////////////////////////////////////////////
function AvoidTextureConstraint(textureID)
{
this.textureID = textureID;
}
AvoidTextureConstraint.prototype.allows = function(x, y)
AvoidTextureConstraint.prototype.allows = function(x, z)
{
return g_Map.texture[x][y] != this.textureID;
return g_Map.texture[x][z] != this.textureID;
};
///////////////////////////////////////////////////////////////////////////
// AvoidTileClassConstraint
//
// Class representing avoid TileClass constraint
//
// tileClassID: ID of the TileClass to avoid
// distance: distance by which it must be avoided
//
///////////////////////////////////////////////////////////////////////////
function AvoidTileClassConstraint(tileClassID, distance)
{
@ -63,13 +89,19 @@ function AvoidTileClassConstraint(tileClassID, distance)
this.distance = distance;
}
AvoidTileClassConstraint.prototype.allows = function(x, y)
AvoidTileClassConstraint.prototype.allows = function(x, z)
{
return this.tileClass.countMembersInRadius(x, y, this.distance) == 0;
return this.tileClass.countMembersInRadius(x, z, this.distance) == 0;
};
///////////////////////////////////////////////////////////////////////////
// StayInTileClassConstraint
//
// Class representing stay in TileClass constraint
//
// tileClassID: ID of TileClass to stay within
// distance: distance from test point to find matching TileClass
//
///////////////////////////////////////////////////////////////////////////
function StayInTileClassConstraint(tileClassID, distance)
{
@ -77,13 +109,20 @@ function StayInTileClassConstraint(tileClassID, distance)
this.distance = distance;
}
StayInTileClassConstraint.prototype.allows = function(x, y)
StayInTileClassConstraint.prototype.allows = function(x, z)
{
return this.tileClass.countNonMembersInRadius(x, y, this.distance) == 0;
return this.tileClass.countNonMembersInRadius(x, z, this.distance) == 0;
};
///////////////////////////////////////////////////////////////////////////
// BorderTileClassConstraint
//
// Class representing border TileClass constraint
//
// tileClassID: ID of TileClass to border
// distanceInside: Distance from test point to find matching TileClass
// distanceOutside: Distance from test point to find other TileClass
//
///////////////////////////////////////////////////////////////////////////
function BorderTileClassConstraint(tileClassID, distanceInside, distanceOutside)
{
@ -92,8 +131,8 @@ function BorderTileClassConstraint(tileClassID, distanceInside, distanceOutside)
this.distanceOutside = distanceOutside;
}
BorderTileClassConstraint.prototype.allows = function(x, y)
BorderTileClassConstraint.prototype.allows = function(x, z)
{
return (this.tileClass.countMembersInRadius(x, y, this.distanceOutside) > 0
&& this.tileClass.countNonMembersInRadius(x, y, this.distanceInside) > 0);
return (this.tileClass.countMembersInRadius(x, z, this.distanceOutside) > 0
&& this.tileClass.countNonMembersInRadius(x, z, this.distanceInside) > 0);
};

View File

@ -1,22 +1,26 @@
function Entity(name, player, x, y, angle)
/////////////////////////////////////////////////////////////////////////////////////////
// Entity
//
// Object for holding entity data
// TODO: support y position or offset (height) and full 3D rotation
//
/////////////////////////////////////////////////////////////////////////////////////////
function Entity(name, player, x, z, orientation)
{
// Get unique ID
this.id = g_Map.getEntityID();
this.name = name;
// Convert from tile coords to map coords
this.x = x;
this.y = y;
// Tile units
this.tileX = x;
this.tileZ = z;
if (player !== undefined)
{
this.player = player;
this.isActor = false;
}
else
{ // Actors have no player ID
this.isActor = true;
}
// Map units (4.0 map units per 1.0 tile)
this.x = x * 4.0;
this.y = 0;
this.z = z * 4.0;
this.orientation = (angle !== undefined ? angle : 0);
this.player = (player !== undefined ? player : 0);
this.orientation = (orientation !== undefined ? orientation : 0);
}

View File

@ -1,7 +1,7 @@
// Some functions to manipulate environment properties
////////////////////////////////////////////////////////////////////////////
// Sky + lighting
// Sky + lighting
////////////////////////////////////////////////////////////////////////////
// Set skyset
function setSkySet(set)
@ -40,7 +40,8 @@ function setUnitsAmbientColour(r, g, b)
}
////////////////////////////////////////////////////////////////////////////
// Water
// Water
////////////////////////////////////////////////////////////////////////////
// Set water colour RGB (0,1)
function setWaterColour(r, g, b)

View File

@ -9,8 +9,6 @@ const SEA_LEVEL = 20.0;
const TERRAIN_SEPARATOR = "|";
const TILES_PER_PATCH = 16;
/////////////////////////////////////////////////////////////////////////////////////////////
// Utility functions
/////////////////////////////////////////////////////////////////////////////////////////////
@ -79,14 +77,14 @@ function floor(x)
return Math.floor(x);
}
function max(x, y)
function max(a, b)
{
return x > y ? x : y;
return a > b ? a : b;
}
function min(x, y)
function min(a, b)
{
return x < y ? x : y;
return a < b ? a : b;
}
function println(x)
@ -143,14 +141,14 @@ function createAreas(centeredPlacer, painter, constraint, num, retryFactor)
var r = halfSize * Math.sqrt(randFloat()); // uniform distribution
var theta = randFloat(0, 2 * PI);
centeredPlacer.x = Math.floor(r * Math.cos(theta)) + halfSize;
centeredPlacer.y = Math.floor(r * Math.sin(theta)) + halfSize;
centeredPlacer.z = Math.floor(r * Math.sin(theta)) + halfSize;
}
else
{ // Rectangular coordinates
centeredPlacer.x = randInt(getMapSize());
centeredPlacer.y = randInt(getMapSize());
centeredPlacer.z = randInt(getMapSize());
}
var area = g_Map.createArea(centeredPlacer, painter, constraint);
if (area !== undefined)
{
@ -183,12 +181,12 @@ function createObjectGroups(placer, player, constraint, num, retryFactor)
var r = halfSize * Math.sqrt(randFloat()); // uniform distribution
var theta = randFloat(0, 2 * PI);
placer.x = Math.floor(r * Math.cos(theta)) + halfSize;
placer.y = Math.floor(r * Math.sin(theta)) + halfSize;
placer.z = Math.floor(r * Math.sin(theta)) + halfSize;
}
else
{ // Rectangular coordinates
placer.x = randInt(getMapSize());
placer.y = randInt(getMapSize());
placer.z = randInt(getMapSize());
}
var result = createObjectGroup(placer, player, constraint);
@ -245,15 +243,15 @@ function createSimpleTerrain(terrain)
}
}
function placeObject(x, y, type, player, angle)
function placeObject(x, z, type, player, angle)
{
g_Map.addObjects(new Entity(type, player, x, y, angle));
g_Map.addObjects(new Entity(type, player, x, z, angle));
}
function placeTerrain(x, y, terrain)
function placeTerrain(x, z, terrain)
{
// convert terrain param into terrain object
g_Map.placeTerrain(x, y, createTerrain(terrain));
g_Map.placeTerrain(x, z, createTerrain(terrain));
}
@ -312,14 +310,14 @@ function getCivCode(player)
return g_MapSettings.PlayerData[player].Civ;
}
function getHeight(x, y)
function getHeight(x, z)
{
return g_Map.getHeight(x, y);
return g_Map.getHeight(x, z);
}
function setHeight(x, y, height)
function setHeight(x, z, height)
{
g_Map.setHeight(x, y, height);
g_Map.setHeight(x, z, height);
}
/////////////////////////////////////////////////////////////////////////////////////////////
@ -328,13 +326,13 @@ function setHeight(x, y, height)
// Add point to given class by id
function addToClass(x, y, id)
function addToClass(x, z, id)
{
var tileClass = getTileClass(id);
if (tileClass !== null)
{
tileClass.add(x, y);
tileClass.add(x, z);
}
}

View File

@ -1,38 +1,43 @@
//////////////////////////////////////////////////////////////////////
// Map
//
// Class for holding map data and providing basic API to change it
//
// size: Size of the map in tiles
// baseHeight: Starting height of the map
//
//////////////////////////////////////////////////////////////////////
function Map(size, baseHeight)
{
// Size must be 0 to 1024, divisible by 16
// Size must be 0 to 1024, divisible by patches
this.size = size;
// Create 2D arrays for texture, object, and area maps
// Create 2D arrays for textures, object, and areas
this.texture = new Array(size);
this.terrainObjects = new Array(size);
this.area = new Array(size);
for (var i = 0; i < size; i++)
{
this.texture[i] = new Uint16Array(size); // uint16
this.terrainObjects[i] = new Array(size); // entity
this.area[i] = new Array(size); // area
this.texture[i] = new Uint16Array(size); // uint16 - texture IDs
this.terrainObjects[i] = new Array(size); // array of entities
this.area[i] = new Uint16Array(size); // uint16 - area IDs
for (var j = 0; j < size; j++)
{
this.area[i][j] = {}; // undefined would cause a warning in strict mode
this.terrainObjects[i][j] = [];
}
}
var mapSize = size+1;
// Create 2D array for heightmap
var mapSize = size+1;
this.height = new Array(mapSize);
for (var i=0; i < mapSize; i++)
for (var i = 0; i < mapSize; i++)
{
this.height[i] = new Float32Array(mapSize);
for (var j=0; j < mapSize; j++)
this.height[i] = new Float32Array(mapSize); // float32
for (var j = 0; j < mapSize; j++)
{ // Initialize height map to baseHeight
this.height[i][j] = baseHeight;
}
@ -44,9 +49,10 @@ function Map(size, baseHeight)
// Other arrays
this.objects = []; //object
this.areas = []; //area
this.tileClasses = []; //int
this.areaID = 0;
// Starting entity ID
this.entityCount = 150;
}
@ -55,9 +61,9 @@ Map.prototype.initTerrain = function(baseTerrain)
{
// Initialize base terrain
var size = this.size;
for (var i=0; i < size; i++)
for (var i = 0; i < size; i++)
{
for (var j=0; j < size; j++)
for (var j = 0; j < size; j++)
{
baseTerrain.place(i, j);
}
@ -65,7 +71,7 @@ Map.prototype.initTerrain = function(baseTerrain)
};
// Return ID of texture (by name)
Map.prototype.getID = function(texture)
Map.prototype.getTextureID = function(texture)
{
if (texture in (this.nameToID))
{
@ -86,16 +92,16 @@ Map.prototype.getEntityID = function()
return this.entityCount++;
}
// Check bounds
Map.prototype.validT = function(x, y)
// Check bounds on tile map
Map.prototype.validT = function(x, z)
{
return x >= 0 && y >= 0 && x < this.size && y < this.size;
return x >= 0 && z >= 0 && x < this.size && z < this.size;
};
// Check bounds on height map (size + 1 by size + 1)
Map.prototype.validH = function(x, y)
Map.prototype.validH = function(x, z)
{
return x >= 0 && y >= 0 && x <= this.size && y <= this.size;
return x >= 0 && z >= 0 && x <= this.size && z <= this.size;
};
// Check bounds on tile class
@ -104,57 +110,69 @@ Map.prototype.validClass = function(c)
return c >= 0 && c < this.tileClasses.length;
};
Map.prototype.getTexture = function(x, y)
Map.prototype.getTexture = function(x, z)
{
if (!this.validT(x, y))
error("getTexture: invalid tile position ("+x+", "+y+")");
if (!this.validT(x, z))
{
error("getTexture: invalid tile position ("+x+", "+z+")");
}
return this.IDToName[this.texture[x][y]];
return this.IDToName[this.texture[x][z]];
};
Map.prototype.setTexture = function(x, y, texture)
Map.prototype.setTexture = function(x, z, texture)
{
if (!this.validT(x, y))
error("setTexture: invalid tile position ("+x+", "+y+")");
if (!this.validT(x, z))
{
error("setTexture: invalid tile position ("+x+", "+z+")");
}
this.texture[x][y] = this.getID(texture);
this.texture[x][z] = this.getTextureID(texture);
};
Map.prototype.getHeight = function(x, y)
Map.prototype.getHeight = function(x, z)
{
if (!this.validH(x, y))
error("getHeight: invalid vertex position ("+x+", "+y+")");
if (!this.validH(x, z))
{
error("getHeight: invalid vertex position ("+x+", "+z+")");
}
return this.height[x][y];
return this.height[x][z];
};
Map.prototype.setHeight = function(x, y, height)
Map.prototype.setHeight = function(x, z, height)
{
if (!this.validH(x, y))
error("setHeight: invalid vertex position ("+x+", "+y+")");
if (!this.validH(x, z))
{
error("setHeight: invalid vertex position ("+x+", "+z+")");
}
this.height[x][y] = height;
this.height[x][z] = height;
};
Map.prototype.getTerrainObjects = function(x, y)
Map.prototype.getTerrainObjects = function(x, z)
{
if (!this.validT(x, y))
error("getTerrainObjects: invalid tile position ("+x+", "+y+")");
if (!this.validT(x, z))
{
error("getTerrainObjects: invalid tile position ("+x+", "+z+")");
}
return this.terrainObjects[x][y];
return this.terrainObjects[x][z];
};
Map.prototype.setTerrainObjects = function(x, y, objects)
Map.prototype.setTerrainObject = function(x, z, object)
{
if (!this.validT(x, y))
error("setTerrainObjects: invalid tile position ("+x+", "+y+")");
if (!this.validT(x, z))
{
error("setTerrainObject: invalid tile position ("+x+", "+z+")");
}
this.terrainObjects[x][y] = objects;
this.terrainObjects[x][z] = object;
};
Map.prototype.placeTerrain = function(x, y, terrain)
Map.prototype.placeTerrain = function(x, z, terrain)
{
terrain.place(x, y);
terrain.place(x, z);
};
Map.prototype.addObjects = function(obj)
@ -186,16 +204,16 @@ Map.prototype.createArea = function(placer, painter, constraint)
if (!points)
return undefined;
var a = new Area(points);
var newID = ++this.areaID;
var area = new Area(points, newID);
for (var i=0; i < points.length; i++)
{
this.area[points[i].x][points[i].y] = a;
this.area[points[i].x][points[i].z] = newID;
}
painter.paint(a);
this.areas.push(a);
painter.paint(area);
return a;
return area;
};
Map.prototype.createObjectGroup = function(placer, player, constraint)
@ -223,19 +241,19 @@ Map.prototype.createTileClass = function()
};
// Get height taking into account terrain curvature
Map.prototype.getExactHeight = function(x, y)
Map.prototype.getExactHeight = function(x, z)
{
var xi = min(Math.floor(x), this.size);
var yi = min(Math.floor(y), this.size);
var zi = min(Math.floor(z), this.size);
var xf = x - xi;
var yf = y - yi;
var zf = z - zi;
var h00 = this.height[xi][yi];
var h01 = this.height[xi][yi+1];
var h10 = this.height[xi+1][yi];
var h11 = this.height[xi+1][yi+1];
var h00 = this.height[xi][zi];
var h01 = this.height[xi][zi+1];
var h10 = this.height[xi+1][zi];
var h11 = this.height[xi+1][zi+1];
return ( 1 - yf ) * ( ( 1 - xf ) * h00 + xf * h10 ) + yf * ( ( 1 - xf ) * h01 + xf * h11 ) ;
return ( 1 - zf ) * ( ( 1 - xf ) * h00 + xf * h10 ) + zf * ( ( 1 - xf ) * h01 + xf * h11 ) ;
};
Map.prototype.getMapData = function()
@ -247,26 +265,20 @@ Map.prototype.getMapData = function()
// Terrain objects first (trees)
var size = this.size;
for (var x=0; x < size; ++x)
for (var x = 0; x < size; ++x)
{
for (var y=0; y < size; ++y)
for (var z = 0; z < size; ++z)
{
if (this.terrainObjects[x][y].length)
entities = entities.concat(this.terrainObjects[x][y]);
if (this.terrainObjects[x][z] !== undefined)
{
entities.push(this.terrainObjects[x][z]);
}
}
}
// Now other entities
entities = entities.concat(this.objects);
// Convert from tiles to map coordinates
for (var n in entities)
for (var i = 0; i < this.objects.length; ++i)
{
var e = entities[n];
e.x *= 4;
e.y *= 4;
entities[n] = e;
entities.push(this.objects[i]);
}
data["entities"] = entities;
@ -277,18 +289,23 @@ Map.prototype.getMapData = function()
// Flat because it's easier to handle by the engine
var mapSize = size+1;
var height16 = new Array(mapSize*mapSize); // uint16
for (var x=0; x < mapSize; x++)
for (var x = 0; x < mapSize; x++)
{
for (var y=0; y < mapSize; y++)
for (var z = 0; z < mapSize; z++)
{
var intHeight = Math.floor((this.height[x][y] + SEA_LEVEL) * 256.0 / 0.35);
var intHeight = Math.floor((this.height[x][z] + SEA_LEVEL) * 256.0 / 0.35);
if (intHeight > 65000)
intHeight = 65000;
// Prevent under/overflow in terrain data
if (intHeight > 0xFFFF)
{
intHeight = 0xFFFF;
}
else if (intHeight < 0)
{
intHeight = 0;
}
height16[y*mapSize + x] = intHeight;
height16[z*mapSize + x] = intHeight;
}
}
data["height"] = height16;
@ -297,26 +314,19 @@ Map.prototype.getMapData = function()
// Get array of textures used in this map
var textureNames = [];
for (var name in this.nameToID)
{
textureNames.push(name);
}
data["textureNames"] = textureNames;
// Convert 2D tile data to flat array, reodering into patches as expected by MapReader
// Convert 2D tile data to flat array
var tiles = new Array(size*size);
var patches = size/16;
for (var x=0; x < size; x++)
for (var x = 0; x < size; x++)
{
var patchX = Math.floor(x/16);
var offX = x%16;
for (var y=0; y < size; y++)
for (var z = 0; z < size; z++)
{
var patchY = Math.floor(y/16);
var offY = y%16;
tiles[(patchY*patches + patchX)*256 + (offY*16 + offX)] =
{ "texIdx1" : this.texture[x][y],
"texIdx2" : 0xFFFF,
"priority" : 0
};
// TODO: For now just use the texture's index as priority, might want to do this another way
tiles[z*size + x] = { "idx": this.texture[x][z], "priority": this.texture[x][z] };
}
}
data["tileData"] = tiles;

View File

@ -46,7 +46,7 @@ function InitMap()
// until SpiderMonkey gets upgraded
g_MapSettings.Size = Math.floor(g_MapSettings.Size);
g_Map = new Map(g_MapSettings.Size * TILES_PER_PATCH, g_MapSettings.BaseHeight);
g_Map = new Map(g_MapSettings.Size, g_MapSettings.BaseHeight);
g_Map.initTerrain(terrain);
}
@ -60,6 +60,9 @@ function ExportMap()
// Add environment and camera settings
g_Environment.Water.WaterBody.Height = SEA_LEVEL - 0.1;
data.Environment = g_Environment;
// Adjust default cam to roughly center of the map - useful for Atlas
g_Camera.Position = {x: g_MapSettings.Size*2, y: g_MapSettings.Size*2, z: -g_MapSettings.Size*2};
data.Camera = g_Camera;
RMS.ExportMap(data);

View File

@ -16,6 +16,9 @@ function modPos(num, m)
/////////////////////////////////////////////////////////////////////
// Noise2D
//
// Class representing 2D noise with a given base frequency
//
/////////////////////////////////////////////////////////////////////
function Noise2D(freq)
@ -31,7 +34,7 @@ function Noise2D(freq)
{
var a = randFloat() * 2 * PI;
this.grads[i][j] = new Vector2D(cos(a), sin(a));
this.grads[i][j] = new Vector2D(Math.cos(a), Math.sin(a));
}
}
}
@ -64,6 +67,9 @@ Noise2D.prototype.get = function(x, y)
/////////////////////////////////////////////////////////////////////
// Noise3D
//
// Class representing 3D noise with given base frequencies
//
/////////////////////////////////////////////////////////////////////
function Noise3D(freq, vfreq)

View File

@ -1,15 +1,21 @@
// Constants for using SmoothElevationPainter
const ELEVATION_SET = 0;
const ELEVATION_MODIFY = 1;
/////////////////////////////////////////////////////////////////////////////
// ElevationPainter
//
// Class for painting elevation over an area
//
// elevation: Target elevation/height to be painted
//
/////////////////////////////////////////////////////////////////////////////
function ElevationPainter(elevation)
{
this.elevation = elevation;
this.DX = [0, 1, 1, 0];
this.DY = [0, 0, 1, 1];
this.DZ = [0, 0, 1, 1];
}
ElevationPainter.prototype.paint = function(area)
@ -23,13 +29,19 @@ ElevationPainter.prototype.paint = function(area)
for (var j=0; j < 4; j++)
{
g_Map.height[pt.x+this.DX[j]][pt.y+this.DY[j]] = elevation;
g_Map.height[pt.x + this.DX[j]][pt.z + this.DZ[j]] = elevation;
}
}
};
/////////////////////////////////////////////////////////////////////////////
// LayeredPainter
//
// Class for painting multiple layered terrains over an area
//
// terrainArray: Array of terrain painter objects
// widths: Array of widths for each layer
//
/////////////////////////////////////////////////////////////////////////////
function LayeredPainter(terrainArray, widths)
@ -39,7 +51,9 @@ function LayeredPainter(terrainArray, widths)
this.terrains = [];
for (var i = 0; i < terrainArray.length; ++i)
{
this.terrains.push(createTerrain(terrainArray[i]));
}
this.widths = widths;
}
@ -63,24 +77,25 @@ LayeredPainter.prototype.paint = function(area)
// push edge points
var pts = area.points;
var length = pts.length;
var areaID = area.getID();
for (var i=0; i < length; i++)
{
var x = pts[i].x;
var y = pts[i].y;
var z = pts[i].z;
for (var dx=-1; dx <= 1; dx++)
{
var nx = x+dx;
for (var dy=-1; dy <= 1; dy++)
for (var dz=-1; dz <= 1; dz++)
{
var ny = y+dy;
var nz = z+dz;
if (g_Map.validT(nx, ny) && g_Map.area[nx][ny] != area && !saw[nx][ny])
if (g_Map.validT(nx, nz) && g_Map.area[nx][nz] != areaID && !saw[nx][nz])
{
saw[nx][ny] = 1;
dist[nx][ny] = 0;
pointQ.push(new Point(nx, ny));
saw[nx][nz] = 1;
dist[nx][nz] = 0;
pointQ.push(new PointXZ(nx, nz));
}
}
}
@ -91,11 +106,11 @@ LayeredPainter.prototype.paint = function(area)
{
var pt = pointQ.shift(); // Pop queue
var px = pt.x;
var py = pt.y;
var d = dist[px][py];
var pz = pt.z;
var d = dist[px][pz];
// paint if in area
if (g_Map.area[px][py] == area)
if (g_Map.area[px][pz] == areaID)
{
var w=0;
var i=0;
@ -108,22 +123,22 @@ LayeredPainter.prototype.paint = function(area)
break;
}
}
this.terrains[i].place(px, py);
this.terrains[i].place(px, pz);
}
// enqueue neighbours
for (var dx=-1; dx<=1; dx++)
{
var nx = px+dx;
for (var dy=-1; dy<=1; dy++)
for (var dz=-1; dz<=1; dz++)
{
var ny = py+dy;
var nz = pz+dz;
if (g_Map.validT(nx, ny) && g_Map.area[nx][ny] == area && !saw[nx][ny])
if (g_Map.validT(nx, nz) && g_Map.area[nx][nz] == areaID && !saw[nx][nz])
{
saw[nx][ny] = 1;
dist[nx][ny] = d+1;
pointQ.push(new Point(nx, ny));
saw[nx][nz] = 1;
dist[nx][nz] = d+1;
pointQ.push(new PointXZ(nx, nz));
}
}
}
@ -132,6 +147,11 @@ LayeredPainter.prototype.paint = function(area)
/////////////////////////////////////////////////////////////////////////////
// MultiPainter
//
// Class for applying multiple painters over an area
//
// painters: Array of painter objects
//
/////////////////////////////////////////////////////////////////////////////
function MultiPainter(painters)
@ -149,6 +169,15 @@ MultiPainter.prototype.paint = function(area)
/////////////////////////////////////////////////////////////////////////////
// SmoothElevationPainter
//
// Class for painting elevation smoothly over an area
//
// type: Type of elevation modification
// ELEVATION_MODIFY = relative
// ELEVATION_SET = absolute
// elevation: Target elevation/height of area
// blendRadius: How steep the elevation change is
//
/////////////////////////////////////////////////////////////////////////////
function SmoothElevationPainter(type, elevation, blendRadius)
@ -161,16 +190,9 @@ function SmoothElevationPainter(type, elevation, blendRadius)
error("SmoothElevationPainter: invalid type '"+type+"'");
}
SmoothElevationPainter.prototype.checkInArea = function(area, x, y)
SmoothElevationPainter.prototype.checkInArea = function(areaID, x, z)
{
if (g_Map.validT(x, y))
{
return (g_Map.area[x][y] == area);
}
else
{
return false;
}
return (g_Map.validT(x, z) && g_Map.area[x][z] == areaID);
};
SmoothElevationPainter.prototype.paint = function(area)
@ -196,25 +218,26 @@ SmoothElevationPainter.prototype.paint = function(area)
}
var length = pts.length;
var areaID = area.getID();
// get a list of all points
for (var i=0; i < length; i++)
{
var x = pts[i].x;
var y = pts[i].y;
var z = pts[i].z;
for (var dx=-1; dx <= 2; dx++)
{
var nx = x+dx;
for (var dy=-1; dy <= 2; dy++)
for (var dz=-1; dz <= 2; dz++)
{
var ny = y+dy;
var nz = z+dz;
if (g_Map.validH(nx, ny) && !gotHeightPt[nx][ny])
if (g_Map.validH(nx, nz) && !gotHeightPt[nx][nz])
{
gotHeightPt[nx][ny] = 1;
heightPts.push(new Point(nx, ny));
newHeight[nx][ny] = g_Map.height[nx][ny];
gotHeightPt[nx][nz] = 1;
heightPts.push(new PointXZ(nx, nz));
newHeight[nx][nz] = g_Map.height[nx][nz];
}
}
}
@ -223,24 +246,25 @@ SmoothElevationPainter.prototype.paint = function(area)
// push edge points
for (var i=0; i < length; i++)
{
var x = pts[i].x, y = pts[i].y;
var x = pts[i].x;
var z = pts[i].z;
for (var dx=-1; dx <= 2; dx++)
{
var nx = x+dx;
for (var dy=-1; dy <= 2; dy++)
for (var dz=-1; dz <= 2; dz++)
{
var ny = y+dy;
var nz = z+dz;
if (g_Map.validH(nx, ny)
&& !this.checkInArea(area, nx, ny)
&& !this.checkInArea(area, nx-1, ny)
&& !this.checkInArea(area, nx, ny-1)
&& !this.checkInArea(area, nx-1, ny-1)
&& !saw[nx][ny])
if (g_Map.validH(nx, nz)
&& !this.checkInArea(areaID, nx, nz)
&& !this.checkInArea(areaID, nx-1, nz)
&& !this.checkInArea(areaID, nx, nz-1)
&& !this.checkInArea(areaID, nx-1, nz-1)
&& !saw[nx][nz])
{
saw[nx][ny]= 1;
dist[nx][ny] = 0;
pointQ.push(new Point(nx, ny));
saw[nx][nz]= 1;
dist[nx][nz] = 0;
pointQ.push(new PointXZ(nx, nz));
}
}
}
@ -251,35 +275,35 @@ SmoothElevationPainter.prototype.paint = function(area)
{
var pt = pointQ.shift();
var px = pt.x;
var py = pt.y;
var d = dist[px][py];
var pz = pt.z;
var d = dist[px][pz];
// paint if in area
if (g_Map.validH(px, py)
&& (this.checkInArea(area, px, py) || this.checkInArea(area, px-1, py)
|| this.checkInArea(area, px, py-1) || this.checkInArea(area, px-1, py-1)))
if (g_Map.validH(px, pz)
&& (this.checkInArea(areaID, px, pz) || this.checkInArea(areaID, px-1, pz)
|| this.checkInArea(areaID, px, pz-1) || this.checkInArea(areaID, px-1, pz-1)))
{
if (d <= this.blendRadius)
{
var a = (d-1) / this.blendRadius;
if (this.type == ELEVATION_SET)
{
newHeight[px][py] = a*this.elevation + (1-a)*g_Map.height[px][py];
newHeight[px][pz] = a*this.elevation + (1-a)*g_Map.height[px][pz];
}
else
{ // type == MODIFY
newHeight[px][py] += a*this.elevation;
newHeight[px][pz] += a*this.elevation;
}
}
else
{ // also happens when blendRadius == 0
if (this.type == ELEVATION_SET)
{
newHeight[px][py] = this.elevation;
newHeight[px][pz] = this.elevation;
}
else
{ // type == MODIFY
newHeight[px][py] += this.elevation;
newHeight[px][pz] += this.elevation;
}
}
}
@ -288,18 +312,18 @@ SmoothElevationPainter.prototype.paint = function(area)
for (var dx=-1; dx <= 1; dx++)
{
var nx = px+dx;
for (var dy=-1; dy <= 1; dy++)
for (var dz=-1; dz <= 1; dz++)
{
var ny = py+dy;
var nz = pz+dz;
if (g_Map.validH(nx, ny)
&& (this.checkInArea(area, nx, ny) || this.checkInArea(area, nx-1, ny)
|| this.checkInArea(area, nx, ny-1) || this.checkInArea(area, nx-1, ny-1))
&& !saw[nx][ny])
if (g_Map.validH(nx, nz)
&& (this.checkInArea(areaID, nx, nz) || this.checkInArea(areaID, nx-1, nz)
|| this.checkInArea(areaID, nx, nz-1) || this.checkInArea(areaID, nx-1, nz-1))
&& !saw[nx][nz])
{
saw[nx][ny] = 1;
dist[nx][ny] = d+1;
pointQ.push(new Point(nx, ny));
saw[nx][nz] = 1;
dist[nx][nz] = d+1;
pointQ.push(new PointXZ(nx, nz));
}
}
}
@ -312,36 +336,41 @@ SmoothElevationPainter.prototype.paint = function(area)
{
var pt = heightPts[i];
var px = pt.x;
var py = pt.y;
var pz = pt.z;
if ((this.checkInArea(area, px, py) || this.checkInArea(area, px-1, py)
|| this.checkInArea(area, px, py-1) || this.checkInArea(area, px-1, py-1)))
if ((this.checkInArea(areaID, px, pz) || this.checkInArea(areaID, px-1, pz)
|| this.checkInArea(areaID, px, pz-1) || this.checkInArea(areaID, px-1, pz-1)))
{
var sum = 8 * newHeight[px][py];
var sum = 8 * newHeight[px][pz];
var count = 8;
for (var dx=-1; dx <= 1; dx++)
{
var nx = px+dx;
for (var dy=-1; dy <= 1; dy++)
for (var dz=-1; dz <= 1; dz++)
{
var ny = py+dy;
var nz = pz+dz;
if (g_Map.validH(nx, ny))
if (g_Map.validH(nx, nz))
{
sum += newHeight[nx][ny];
sum += newHeight[nx][nz];
count++;
}
}
}
g_Map.height[px][py] = sum/count;
g_Map.height[px][pz] = sum/count;
}
}
};
/////////////////////////////////////////////////////////////////////////////
// TerrainPainter
//
// Class for painting a terrain over an area
//
// terrain: Terrain placer object
//
/////////////////////////////////////////////////////////////////////////////
function TerrainPainter(terrain)
@ -355,12 +384,17 @@ TerrainPainter.prototype.paint = function(area)
for (var i=0; i < length; i++)
{
var pt = area.points[i];
this.terrain.place(pt.x, pt.y);
this.terrain.place(pt.x, pt.z);
}
};
/////////////////////////////////////////////////////////////////////////////
// TileClassPainter
//
// Class for painting tileClasses over an area
//
// tileClass: TileClass object
//
/////////////////////////////////////////////////////////////////////////////
function TileClassPainter(tileClass)
@ -374,6 +408,6 @@ TileClassPainter.prototype.paint = function(area)
for (var i=0; i < length; i++)
{
var pt = area.points[i];
this.tileClass.add(pt.x, pt.y);
this.tileClass.add(pt.x, pt.z);
}
};

View File

@ -1,22 +1,30 @@
/////////////////////////////////////////////////////////////////////////////////////////
// ClumpPlacer
//
// Class for generating a roughly circular clump of points
//
// size: The average number of points in the clump
// coherence: How much the radius of the clump varies (1.0 = circle, 0.0 = very random)
// smoothness: How smooth the border of the clump is (1.0 = few "peaks", 0.0 = very jagged)
// failfraction: Percentage of place attempts allowed to fail (optional)
// x, z: Tile coordinates of placer center (optional)
//
/////////////////////////////////////////////////////////////////////////////////////////
function ClumpPlacer(size, coherence, smoothness, failFraction, x, y)
function ClumpPlacer(size, coherence, smoothness, failFraction, x, z)
{
this.size = size;
this.coherence = coherence;
this.smoothness = smoothness;
this.failFraction = (failFraction !== undefined ? failFraction : 0);
this.x = (x !== undefined ? x : -1);
this.y = (y !== undefined ? y : -1);
this.z = (z !== undefined ? z : -1);
}
ClumpPlacer.prototype.place = function(constraint)
{
// Preliminary bounds check
if (!g_Map.validT(this.x, this.y) || !constraint.allows(this.x, this.y))
if (!g_Map.validT(this.x, this.z) || !constraint.allows(this.x, this.z))
{
return undefined;
}
@ -37,7 +45,9 @@ ClumpPlacer.prototype.place = function(constraint)
var ctrlPts = 1 + Math.floor(1.0/Math.max(this.smoothness,1.0/intPerim));
if (ctrlPts > radius * 2 * PI)
ctrlPts = Math.floor(radius * 2 * PI) + 1;
{
ctrlPts = Math.floor(radius * 2 * PI) + 1;
}
var noise = new Float32Array(intPerim); //float32
var ctrlCoords = new Float32Array(ctrlPts+1); //float32
@ -83,7 +93,7 @@ ClumpPlacer.prototype.place = function(constraint)
var s = sin(th);
var c = cos(th);
var xx=this.x;
var yy=this.y;
var yy=this.z;
for (var k=0; k < ceil(r); k++)
{
@ -94,7 +104,7 @@ ClumpPlacer.prototype.place = function(constraint)
if (!gotRet[i][j])
{ // Only include each point once
gotRet[i][j] = 1;
retVec.push(new Point(i, j));
retVec.push(new PointXZ(i, j));
}
}
else
@ -111,24 +121,30 @@ ClumpPlacer.prototype.place = function(constraint)
/////////////////////////////////////////////////////////////////////////////////////////
// RectPlacer
//
// Class for generating a rectangular block of points
//
// x1,z1: Top left corner of block
// x2,z2: Bottom right corner of block
//
/////////////////////////////////////////////////////////////////////////////////////////
function RectPlacer(x1, y1, x2, y2)
function RectPlacer(x1, z1, x2, z2)
{
this.x1 = x1;
this.y1 = y1;
this.z1 = z1;
this.x2 = x2;
this.y2 = y2;
this.z2 = z2;
if (x1 > x2 || y1 > y2)
if (x1 > x2 || z1 > z2)
error("RectPlacer: incorrect bounds on rect");
}
RectPlacer.prototype.place = function(constraint)
{
// Preliminary bounds check
if (!g_Map.validT(this.x1, this.y1) || !constraint.allows(this.x1, this.y1) ||
!g_Map.validT(this.x2, this.y2) || !constraint.allows(this.x2, this.y2))
if (!g_Map.validT(this.x1, this.z1) || !constraint.allows(this.x1, this.z1) ||
!g_Map.validT(this.x2, this.z2) || !constraint.allows(this.x2, this.z2))
{
return undefined;
}
@ -136,15 +152,15 @@ RectPlacer.prototype.place = function(constraint)
var ret = [];
var x2 = this.x2;
var y2 = this.y2;
var z2 = this.z2;
for (var x=this.x1; x < x2; x++)
{
for (var y=this.y1; y < y2; y++)
for (var z=this.z1; z < z2; z++)
{
if (g_Map.validT(x, y) && constraint.allows(x, y))
if (g_Map.validT(x, z) && constraint.allows(x, z))
{
ret.push(new Point(x, y));
ret.push(new PointXZ(x, z));
}
else
{
@ -163,7 +179,15 @@ RectPlacer.prototype.place = function(constraint)
function ObjectGroupPlacer() {}
/////////////////////////////////////////////////////////////////////////////////////////
// SimpleGroup
// SimpleObject
//
// Class specifying a type of entity that can be placed on the map
//
// type: The entity's template name
// minCount,maxCount: The number of objects to place
// minDistance,maxDistance: The distance between placed objects
// minAngle,maxAngle: The variation in angle of placed objects (optional)
//
/////////////////////////////////////////////////////////////////////////////////////////
function SimpleObject(type, minCount, maxCount, minDistance, maxDistance, minAngle, maxAngle)
@ -186,7 +210,7 @@ function SimpleObject(type, minCount, maxCount, minDistance, maxDistance, minAng
error("SimpleObject: minAngle must be less than or equal to maxAngle");
}
SimpleObject.prototype.place = function(cx, cy, player, avoidSelf, constraint)
SimpleObject.prototype.place = function(cx, cz, player, avoidSelf, constraint)
{
var failCount = 0;
var count = randInt(this.minCount, this.maxCount);
@ -200,10 +224,10 @@ SimpleObject.prototype.place = function(cx, cy, player, avoidSelf, constraint)
var direction = randFloat(0, 2*PI);
var x = cx + 0.5 + distance*cos(direction);
var y = cy + 0.5 + distance*sin(direction);
var z = cz + 0.5 + distance*sin(direction);
var fail = false; // reset place failure flag
if (x < 0 || y < 0 || x > g_Map.size || y > g_Map.size)
if (!g_Map.validT(x, z))
{
fail = true;
}
@ -215,7 +239,7 @@ SimpleObject.prototype.place = function(cx, cy, player, avoidSelf, constraint)
for (var i = 0; (i < length) && !fail; i++)
{
var dx = x - resultObjs[i].x;
var dy = y - resultObjs[i].y;
var dy = z - resultObjs[i].z;
if ((dx*dx + dy*dy) < 1)
{
@ -226,14 +250,14 @@ SimpleObject.prototype.place = function(cx, cy, player, avoidSelf, constraint)
if (!fail)
{
if (!constraint.allows(Math.floor(x), Math.floor(y)))
if (!constraint.allows(Math.floor(x), Math.floor(z)))
{
fail = true;
}
else
{ // if we got here, we're good
var angle = randFloat(this.minAngle, this.maxAngle);
resultObjs.push(new Entity(this.type, player, x, y, angle));
resultObjs.push(new Entity(this.type, player, x, z, angle));
break;
}
}
@ -253,13 +277,25 @@ SimpleObject.prototype.place = function(cx, cy, player, avoidSelf, constraint)
return resultObjs;
};
function SimpleGroup(elements, avoidSelf, tileClass, x, y)
/////////////////////////////////////////////////////////////////////////////////////////
// SimpleGroup
//
// Class for placing groups of different objects
//
// elements: Array of SimpleObjects
// avoidSelf: Objects will not overlap
// tileClass: Optional tile class to add with these objects
// x,z: Tile coordinates of center of placer
//
/////////////////////////////////////////////////////////////////////////////////////////
function SimpleGroup(elements, avoidSelf, tileClass, x, z)
{
this.elements = elements;
this.tileClass = (tileClass !== undefined ? getTileClass(tileClass) : undefined);
this.avoidSelf = (avoidSelf !== undefined ? avoidSelf : false);
this.x = (x !== undefined ? x : -1);
this.y = (y !== undefined ? y : -1);
this.z = (z !== undefined ? z : -1);
}
SimpleGroup.prototype.place = function(player, constraint)
@ -270,7 +306,7 @@ SimpleGroup.prototype.place = function(player, constraint)
var length = this.elements.length;
for (var i=0; i < length; i++)
{
var objs = this.elements[i].place(this.x, this.y, player, this.avoidSelf, constraint);
var objs = this.elements[i].place(this.x, this.z, player, this.avoidSelf, constraint);
if (objs === undefined)
{ // Failure
return false;
@ -289,7 +325,7 @@ SimpleGroup.prototype.place = function(player, constraint)
if (this.tileClass !== undefined)
{ // Round object position to integer
this.tileClass.add(Math.floor(resultObjs[i].x), Math.floor(resultObjs[i].y));
this.tileClass.add(Math.floor(resultObjs[i].tileX), Math.floor(resultObjs[i].tileZ));
}
}

View File

@ -1,5 +1,26 @@
function Point(x, y)
/////////////////////////////////////////////////////////////////////
// PointXZ
//
// Class for representing 2D point in tile coordinates (X,Z)
//
/////////////////////////////////////////////////////////////////////
function PointXZ(x, z)
{
this.x = (x !== undefined ? x : 0);
this.z = (z !== undefined ? z : 0);
}
/////////////////////////////////////////////////////////////////////
// Point3D
//
// Class for representing generic 3D point
//
/////////////////////////////////////////////////////////////////////
function Point3D(x, y, z)
{
this.x = (x !== undefined ? x : 0);
this.y = (y !== undefined ? y : 0);
this.z = (z !== undefined ? z : 0);
}

View File

@ -1,27 +1,39 @@
//////////////////////////////////////////////////////////////////////
// Terrain
//
// Abstract class for terrain placers
//
//////////////////////////////////////////////////////////////////////
function Terrain() {}
Terrain.prototype.place = function(x, y)
Terrain.prototype.place = function(x, z)
{
// Clear old array
g_Map.terrainObjects[x][y] = [];
g_Map.terrainObjects[x][z] = undefined;
this.placeNew(x, y);
this.placeNew(x, z);
};
Terrain.prototype.placeNew = function() {};
//////////////////////////////////////////////////////////////////////
// SimpleTerrain
//
// Class for placing simple terrains
// (one texture and one tree per tile)
//
// texture: Terrain texture name
// treeType: Optional template of the tree entity for this terrain
//
//////////////////////////////////////////////////////////////////////
function SimpleTerrain(texture, treeType)
{
if (texture === undefined)
{
error("SimpleTerrain: texture not defined");
}
this.texture = texture;
this.treeType = treeType;
@ -29,29 +41,38 @@ function SimpleTerrain(texture, treeType)
SimpleTerrain.prototype = new Terrain();
SimpleTerrain.prototype.constructor = SimpleTerrain;
SimpleTerrain.prototype.placeNew = function(x, y)
SimpleTerrain.prototype.placeNew = function(x, z)
{
if (this.treeType !== undefined)
g_Map.terrainObjects[x][y].push(new Entity(this.treeType, 0, x+0.5, y+0.5, randFloat()*PI));
{
g_Map.terrainObjects[x][z] = new Entity(this.treeType, 0, x+0.5, z+0.5, randFloat()*PI);
}
g_Map.texture[x][y] = g_Map.getID(this.texture);
g_Map.texture[x][z] = g_Map.getTextureID(this.texture);
};
//////////////////////////////////////////////////////////////////////
// RandomTerrain
//
// Class for placing random SimpleTerrains
//
// terrains: Array of SimpleTerrain objects
//
//////////////////////////////////////////////////////////////////////
function RandomTerrain(terrains)
{
if (!(terrains instanceof Array) || !terrains.length)
{
error("Invalid terrains array");
}
this.terrains = terrains;
}
RandomTerrain.prototype = new Terrain();
RandomTerrain.prototype.constructor = RandomTerrain;
RandomTerrain.prototype.placeNew = function(x, y)
RandomTerrain.prototype.placeNew = function(x, z)
{
this.terrains[randInt(this.terrains.length)].placeNew(x, y);
this.terrains[randInt(this.terrains.length)].placeNew(x, z);
};

View File

@ -1,5 +1,8 @@
//////////////////////////////////////////////////////////////////////
// RangeOp
//
// Class for efficiently finding number of points within a range
//
//////////////////////////////////////////////////////////////////////
function RangeOp(size)
@ -60,6 +63,10 @@ RangeOp.prototype.get = function(start, end)
//////////////////////////////////////////////////////////////////////
// TileClass
//
// Class for representing terrain types and containing all the tiles
// within that type
//
//////////////////////////////////////////////////////////////////////
function TileClass(size, id)
@ -76,22 +83,22 @@ function TileClass(size, id)
}
}
TileClass.prototype.add = function(x, y)
TileClass.prototype.add = function(x, z)
{
if (!this.inclusionCount[x][y])
if (!this.inclusionCount[x][z])
{
this.rangeCount[y].add(x, 1);
this.rangeCount[z].add(x, 1);
}
this.inclusionCount[x][y]++;
this.inclusionCount[x][z]++;
};
TileClass.prototype.remove = function(x, y)
TileClass.prototype.remove = function(x, z)
{
this.inclusionCount[x][y]--;
if(!this.inclusionCount[x][y])
this.inclusionCount[x][z]--;
if(!this.inclusionCount[x][z])
{
this.rangeCount[y].add(x, -1);
this.rangeCount[z].add(x, -1);
}
};

View File

@ -1,9 +1,12 @@
/////////////////////////////////////////////////////////////////////
// Vector2D
//
// Class for representing and manipulating 2D vectors
//
/////////////////////////////////////////////////////////////////////
// TODO: Type errors if v not instanceof Vector classes
// TODO: Possible implement in C++
// TODO: Possibly implement in C++
function Vector2D(x, y)
{
@ -68,13 +71,16 @@ Vector2D.prototype.normalize = function()
/////////////////////////////////////////////////////////////////////
// Vector3D
//
// Class for representing and manipulating 3D vectors
//
/////////////////////////////////////////////////////////////////////
function Vector3D(x, y, z)
{
if (arguments.length == 3)
{
this.set(x, y, z);
this.set(x, y, y);
}
else
{

View File

@ -57,13 +57,13 @@
</playercolours>
<mapsizes>
<size name="Tiny" patches="8"/>
<size name="Small" patches="12"/>
<size name="Medium" patches="16"/>
<size name="Normal" patches="20"/>
<size name="Large" patches="24"/>
<size name="Very Large" patches="28"/>
<size name="Giant" patches="32"/>
<size name="Tiny" tiles="128"/>
<size name="Small" tiles="192"/>
<size name="Medium" tiles="256"/>
<size name="Normal" tiles="320"/>
<size name="Large" tiles="384"/>
<size name="Very Large" tiles="448"/>
<size name="Giant" tiles="512"/>
</mapsizes>
</lists>

View File

@ -395,10 +395,10 @@ function init(window)
boxSizer.add(10, 0);
// TODO: Get this data from single location (currently specified here, Atlas\lists.xml, and game setup)
var sizeNames = ["Tiny", "Small", "Medium", "Normal", "Large", "Very Large", "Giant"];
var sizePatches = [8, 12, 16, 20, 24, 28, 32];
var sizeTiles = [128, 192, 256, 320, 384, 448, 512];
var sizeChoice = new wxChoice(rmsPanel, -1, wxDefaultPosition, wxDefaultSize, sizeNames);
var numChoices = sizeNames.length;
sizeChoice.toolTip = 'Select the desired map size\n'+sizeNames[0]+' = '+sizePatches[0]+' patches, '+sizeNames[numChoices-1]+' = '+sizePatches[numChoices-1]+' patches';
sizeChoice.toolTip = 'Select the desired map size\n'+sizeNames[0]+' = '+sizeTiles[0]+' patches, '+sizeNames[numChoices-1]+' = '+sizeTiles[numChoices-1]+' patches';
sizeChoice.selection = 0;
boxSizer.add(sizeChoice, 1);
rmsSizer.add(boxSizer, 0, wxStretch.EXPAND | wxDirection.ALL, 2);
@ -430,18 +430,14 @@ function init(window)
terrainArray.push(RMSData.BaseTerrain);
}
// Stringify player data
var pDataStr = JSON.stringify(Atlas.State.mapSettings.settings.PlayerData);
// Complete map settings
Atlas.State.mapSettings.settings.Seed = Atlas.State.Seed ? Atlas.State.Seed : 0;
Atlas.State.mapSettings.settings.Size = sizeTiles[sizeChoice.selection];
Atlas.State.mapSettings.settings.BaseTerrain = terrainArray;
Atlas.State.mapSettings.settings.BaseHeight = RMSData.BaseHeight;
// Generate map
var ret = Atlas.Message.GenerateMap(
RMSData.Script,
sizePatches[sizeChoice.selection],
Atlas.State.Seed ? Atlas.State.Seed : 0,
terrainArray,
RMSData.BaseHeight,
pDataStr
);
var ret = Atlas.Message.GenerateMap(RMSData.Script, JSON.stringify(Atlas.State.mapSettings.settings));
// Check for error
if (ret.status < 0)

View File

@ -27,7 +27,6 @@ struct Entity
float positionX;
float positionZ;
float orientationY;
bool isActor;
};

View File

@ -252,9 +252,8 @@ int CMapReader::ApplyData()
{
if (m_PatchesPerSide == 0)
{
debug_warn(L"Map has no terrain data");
return -1;
// we'll probably crash when trying to use this map later
throw PSERROR_Game_World_MapLoadFailed("Error loading map: no terrain data.\nCheck application log for details.");
}
if (!only_xml)
@ -1128,7 +1127,7 @@ int CMapReader::ParseTerrain()
{ LOGERROR(L"CMapReader::ParseTerrain() failed to get '%hs' property", #prop);\
throw PSERROR_Game_World_MapLoadFailed("Error parsing terrain data.\nCheck application log for details"); }
int size;
size_t size;
GET_TERRAIN_PROPERTY(size, size)
m_PatchesPerSide = size / PATCH_SIZE;
@ -1153,12 +1152,24 @@ int CMapReader::ParseTerrain()
// build tile data
m_Tiles.resize(SQR(size));
// flat array of tile descriptors
std::vector<CMapIO::STileDesc> tileData;
GET_TERRAIN_PROPERTY(tileData, tileData)
for (size_t i = 0; i < tileData.size(); ++i)
debug_assert(SQR(size) == tileData.size());
// reorder by patches and store
for (size_t x = 0; x < size; ++x)
{
m_Tiles[i] = tileData[i];
size_t patchX = x / PATCH_SIZE;
size_t offX = x % PATCH_SIZE;
for (size_t y = 0; y < size; ++y)
{
size_t patchY = y / PATCH_SIZE;
size_t offY = y % PATCH_SIZE;
m_Tiles[(patchY * m_PatchesPerSide + patchX) * SQR(PATCH_SIZE) + (offY * PATCH_SIZE + offX)] = tileData[y*size + x];
}
}
// reset generator state

View File

@ -970,7 +970,7 @@ bool Autostart(const CmdLineArgs& args)
* -autostart-client -- multiplayer client mode
* -autostart-ip=127.0.0.1 -- multiplayer connect to 127.0.0.1
* -autostart-random=104 -- random map, optional seed value = 104 (default is 0, random is -1)
* -autostart-size=12 -- random map size in patches = 12 (default is 12)
* -autostart-size=192 -- random map size in tiles = 192 (default is 192)
*
* Examples:
* -autostart=Acropolis -autostart-host -autostart-players=2 -- Host game on Acropolis map, 2 players
@ -1030,8 +1030,8 @@ bool Autostart(const CmdLineArgs& args)
throw PSERROR_Game_World_MapLoadFailed("Error reading random map script.\nCheck application log for details.");
}
// Get optional map size argument (default 12)
uint mapSize = 12;
// Get optional map size argument (default 192)
uint mapSize = 192;
if (args.Has("autostart-size"))
{
CStr size = args.Get("autostart-size");

View File

@ -149,23 +149,18 @@ template<> bool ScriptInterface::FromJSVal<Entity>(JSContext* cx, jsval v, Entit
if (!JS_ValueToObject(cx, v, &obj) || obj == NULL)
FAIL("Argument must be an object");
jsval name, id, player, x, z, orient, actor;
jsval name, id, player, x, z, orient;
if(!JS_GetProperty(cx, obj, "isActor", &actor) || !FromJSVal(cx, actor, out.isActor))
FAIL("Failed to read Entity.isActor property");
if (!out.isActor)
if(!JS_GetProperty(cx, obj, "player", &player) || !FromJSVal(cx, player, out.playerID))
FAIL("Failed to read Entity.player property");
if(!JS_GetProperty(cx, obj, "player", &player) || !FromJSVal(cx, player, out.playerID))
FAIL("Failed to read Entity.player property");
if (!JS_GetProperty(cx, obj, "name", &name) || !FromJSVal(cx, name, out.templateName))
FAIL("Failed to read Entity.name property");
if (!JS_GetProperty(cx, obj, "id", &id) || !FromJSVal(cx, id, out.entityID))
FAIL("Failed to read Entity.id property");
if (!JS_GetProperty(cx, obj, "x", &x) || !FromJSVal(cx, x, out.positionX))
FAIL("Failed to read Entity.x property");
if (!JS_GetProperty(cx, obj, "y", &z) || !FromJSVal(cx, z, out.positionZ))
FAIL("Failed to read Entity.y property");
if (!JS_GetProperty(cx, obj, "z", &z) || !FromJSVal(cx, z, out.positionZ))
FAIL("Failed to read Entity.z property");
if (!JS_GetProperty(cx, obj, "orientation", &orient) || !FromJSVal(cx, orient, out.orientationY))
FAIL("Failed to read Entity.orientation property");
@ -178,11 +173,9 @@ template<> bool ScriptInterface::FromJSVal<CMapIO::STileDesc>(JSContext* cx, jsv
if (!JS_ValueToObject(cx, v, &obj) || obj == NULL)
FAIL("Argument must be an object");
jsval texIdx1, texIdx2, priority;
if (!JS_GetProperty(cx, obj, "texIdx1", &texIdx1) || !FromJSVal(cx, texIdx1, out.m_Tex1Index))
jsval texIdx, priority;
if (!JS_GetProperty(cx, obj, "idx", &texIdx) || !FromJSVal(cx, texIdx, out.m_Tex1Index))
FAIL("Failed to read CMapIO::STileDesc.m_Tex1Index property");
if (!JS_GetProperty(cx, obj, "texIdx2", &texIdx2) || !FromJSVal(cx, texIdx2, out.m_Tex2Index))
FAIL("Failed to read CMapIO::STileDesc.m_Tex2Index property");
if (!JS_GetProperty(cx, obj, "priority", &priority) || !FromJSVal(cx, priority, out.m_Priority))
FAIL("Failed to read CMapIO::STileDesc.m_Priority property");

View File

@ -492,6 +492,8 @@ template jsval ScriptInterface::ToJSVal<wxMouseEvent>(JSContext*, wxMouseEvent c
template jsval ScriptInterface::ToJSVal<int>(JSContext*, int const&);
template jsval ScriptInterface::ToJSVal<float>(JSContext*, float const&);
template jsval ScriptInterface::ToJSVal<std::vector<int> >(JSContext*, std::vector<int> const&);
template jsval ScriptInterface::ToJSVal<size_t>(JSContext*, size_t const&);
template jsval ScriptInterface::ToJSVal<std::vector<wxString> >(JSContext*, std::vector<wxString> const&);
////////////////////////////////////////////////////////////////

View File

@ -53,16 +53,16 @@ NewDialog::NewDialog(wxWindow* parent, const wxString& title, const wxSize& size
AtObj sizes(Datafile::ReadList("mapsizes"));
for (AtIter s = sizes["size"]; s.defined(); ++s)
{
if (s["@name"].defined() && s["@patches"].defined())
if (s["@name"].defined() && s["@tiles"].defined())
{
m_SizeArray.Add(wxString(s["@name"]));
size_t patch;
size_t size;
std::wstringstream stream;
stream << (std::wstring)s["@patches"];
stream >> patch;
stream << (std::wstring)s["@tiles"];
stream >> size;
m_PatchesArray.push_back(patch);
m_TilesArray.push_back(size);
}
}
@ -112,7 +112,7 @@ void NewDialog::OnHeightChange(wxSpinEvent& event)
size_t NewDialog::GetSelectedSize()
{
return m_PatchesArray[m_SelectedSize];
return m_TilesArray[m_SelectedSize];
}
size_t NewDialog::GetBaseHeight()

View File

@ -45,7 +45,7 @@ private:
size_t m_BaseHeight;
wxArrayString m_SizeArray;
std::vector<size_t> m_PatchesArray;
std::vector<size_t> m_TilesArray;
};

View File

@ -691,22 +691,26 @@ void ScenarioEditor::OnNew(wxCommandEvent& WXUNUSED(event))
wxBusyInfo busy(_("Creating blank map"));
// Generate new blank map
size_t patches = dlg.GetSelectedSize();
size_t tiles = dlg.GetSelectedSize();
size_t height = dlg.GetBaseHeight();
// Get terrain texture
// TODO: Support choosing multiple textures
std::vector<std::wstring> textures;
std::wstring baseTexture(g_SelectedTexture.wc_str());
textures.push_back(baseTexture);
std::vector<wxString> textures;
textures.push_back(g_SelectedTexture);
// Get player data
std::string pData;
m_ScriptInterface.Eval(_T("JSON.stringify(Atlas.State.mapSettings.settings.PlayerData)"), pData);
// TODO: This seems like a nasty way to do this
std::string settings;
m_ScriptInterface.SetValue(_T("Atlas.State.mapSettings.settings.Size"), tiles);
m_ScriptInterface.SetValue(_T("Atlas.State.mapSettings.settings.Seed"), 0);
m_ScriptInterface.SetValue(_T("Atlas.State.mapSettings.settings.BaseTerrain"), textures);
m_ScriptInterface.SetValue(_T("Atlas.State.mapSettings.settings.BaseHeight"), height);
m_ScriptInterface.Eval(_T("JSON.stringify(Atlas.State.mapSettings.settings)"), settings);
// Generate map
// Script name, size (patches), seed, base terrain(s), base height, player data
qGenerateMap qry(L"blank.js", patches, 0, textures, height, pData);
qGenerateMap qry(L"blank.js", settings);
// Wait for map generation to finish
qry.Post();

View File

@ -79,22 +79,12 @@ QUERYHANDLER(GenerateMap)
// Random map
ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface();
CScriptValRooted settings = scriptInterface.ParseJSON(*msg->settings);
CScriptValRooted attrs;
scriptInterface.Eval("({})", attrs);
scriptInterface.SetProperty(attrs.get(), "mapType", std::string("random"));
scriptInterface.SetProperty(attrs.get(), "script", std::wstring(*msg->script));
CScriptValRooted settings;
scriptInterface.Eval("({})", settings);
scriptInterface.SetProperty(settings.get(), "Size", (int)msg->size);
scriptInterface.SetProperty(settings.get(), "Seed", (int)msg->seed);
scriptInterface.SetProperty(settings.get(), "BaseTerrain", std::vector<std::wstring>(*msg->terrain));
scriptInterface.SetProperty(settings.get(), "BaseHeight", (int)msg->height);
scriptInterface.SetProperty(settings.get(), "CircularMap", true); // now default to circular map
CScriptValRooted pData = scriptInterface.ParseJSON(*msg->playerData);
scriptInterface.SetProperty(settings.get(), "PlayerData", pData);
scriptInterface.SetProperty(attrs.get(), "script", std::wstring(*msg->filename));
scriptInterface.SetProperty(attrs.get(), "settings", settings, false);
try

View File

@ -133,14 +133,10 @@ MESSAGE(ResizeScreen,
// Messages for map panel
QUERY(GenerateMap,
((std::wstring, script)) // name of script
((int, size)) // size in number of patches
((int, seed)) // seed for rng
((std::vector<std::wstring>, terrain)) // base terrain(s)
((int, height)) // base height
((std::string, playerData)) // JSON player data
((std::wstring, filename)) // random map script filename
((std::string, settings)) // map settings as JSON string
,
((int, status)) // Status code, 0 for success, or < 0 for failure
((int, status))
);
MESSAGE(LoadMap,