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 // Constants
// TODO: Move some of these into common location (other scripts may need) // 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_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 // Max number of players for any map
const MAX_PLAYERS = 8; const MAX_PLAYERS = 8;
@ -28,7 +28,7 @@ var g_GameAttributes = {
map: "", map: "",
mapPath: "", mapPath: "",
settings: { settings: {
Size: 12, Size: 192,
Seed: 0, Seed: 0,
BaseTerrain: "grass1_spring", BaseTerrain: "grass1_spring",
BaseHeight: 0, BaseHeight: 0,

View File

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

View File

@ -90,18 +90,18 @@ var clSettlement = createTileClass();
log("Placing players..."); log("Placing players...");
var playerX = new Array(numPlayers+1); var playerX = new Array(numPlayers+1);
var playerY = new Array(numPlayers+1); var playerZ = new Array(numPlayers+1);
var numLeftPlayers = ceil(numPlayers/2); var numLeftPlayers = ceil(numPlayers/2);
for (var i=1; i <= numLeftPlayers; i++) for (var i=1; i <= numLeftPlayers; i++)
{ {
playerX[i] = 0.28 + (2*randFloat()-1)*0.01; 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++) for (var i=numLeftPlayers+1; i <= numPlayers; i++)
{ {
playerX[i] = 0.72 + (2*randFloat()-1)*0.01; 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++) for (var i=1; i <= numPlayers; i++)
@ -110,16 +110,16 @@ for (var i=1; i <= numPlayers; i++)
// get fractional locations in tiles // get fractional locations in tiles
var ix = round(fractionToTiles(playerX[i])); var ix = round(fractionToTiles(playerX[i]));
var iy = round(fractionToTiles(playerY[i])); var iz = round(fractionToTiles(playerZ[i]));
addToClass(ix, iy, clPlayer); addToClass(ix, iz, clPlayer);
// create TC and starting units // create TC and starting units
// TODO: Get civ specific starting units // TODO: Get civ specific starting units
var civ = getCivCode(i - 1); 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( var group = new SimpleGroup(
[new SimpleObject("units/"+civ+"_support_female_citizen", 3,3, 5,5)], [new SimpleObject("units/"+civ+"_support_female_citizen", 3,3, 5,5)],
true, null, ix, iy true, null, ix, iz
); );
createObjectGroup(group, i); createObjectGroup(group, i);
@ -127,10 +127,10 @@ for (var i=1; i <= numPlayers; i++)
var bbAngle = randFloat()*2*PI; var bbAngle = randFloat()*2*PI;
var bbDist = 9; var bbDist = 9;
var bbX = round(ix + bbDist * cos(bbAngle)); var bbX = round(ix + bbDist * cos(bbAngle));
var bbY = round(iy + bbDist * sin(bbAngle)); var bbZ = round(iz + bbDist * sin(bbAngle));
group = new SimpleGroup( group = new SimpleGroup(
[new SimpleObject(oBerryBush, 5,5, 0,2)], [new SimpleObject(oBerryBush, 5,5, 0,2)],
true, clBaseResource, bbX, bbY true, clBaseResource, bbX, bbZ
); );
createObjectGroup(group, 0); createObjectGroup(group, 0);
@ -141,44 +141,50 @@ for (var i=1; i <= numPlayers; i++)
} }
var mDist = 9; var mDist = 9;
var mX = round(ix + mDist * cos(mAngle)); var mX = round(ix + mDist * cos(mAngle));
var mY = round(iy + mDist * sin(mAngle)); var mZ = round(iz + mDist * sin(mAngle));
group = new SimpleGroup( group = new SimpleGroup(
[new SimpleObject(oStone, 2,2, 0,3), [new SimpleObject(oStone, 2,2, 0,3),
new SimpleObject(oMetal, 2,2, 0,3)], new SimpleObject(oMetal, 2,2, 0,3)],
true, clBaseResource, mX, mY true, clBaseResource, mX, mZ
); );
createObjectGroup(group, 0); createObjectGroup(group, 0);
// create starting straggler trees // create starting straggler trees
group = new SimpleGroup( group = new SimpleGroup(
[new SimpleObject(oPalm, 3,3, 7,10)], [new SimpleObject(oPalm, 3,3, 7,10)],
true, clBaseResource, ix, iy true, clBaseResource, ix, iz
); );
createObjectGroup(group, 0, avoidClasses(clBaseResource,2)); createObjectGroup(group, 0, avoidClasses(clBaseResource,2));
} }
function distanceToPlayers(x, y) function distanceToPlayers(x, z)
{ {
var r = 10000; var r = 10000;
for (var i=1; i <= numPlayers; i++) for (var i=1; i <= numPlayers; i++)
{ {
var dx = x - playerX[i]; var dx = x - playerX[i];
var dy = y - playerY[i]; var dz = z - playerZ[i];
r = min(r, dx*dx + dy*dy); r = min(r, dx*dx + dz*dz);
} }
return sqrt(r); 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) if (d < 13)
{
return 0; return 0;
}
else if (d < 19) else if (d < 19)
{
return (d-13)/(19-13); return (d-13)/(19-13);
}
else else
{
return 1; return 1;
}
} }
// Paint elevation // Paint elevation
@ -198,11 +204,11 @@ var noise5 = new Noise2D(11 * mapSize/128);
for (var ix=0; ix<=mapSize; ix++) 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 x = ix / (mapSize + 1.0);
var y = iy / (mapSize + 1.0); var z = iz / (mapSize + 1.0);
var pn = playerNearness(x, y); var pn = playerNearness(x, z);
var h = 0; var h = 0;
var distToWater = 0; var distToWater = 0;
@ -226,7 +232,7 @@ for (var ix=0; ix<=mapSize; ix++)
} }
// add some base noise // 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 ) if ( baseNoise < 0 )
{ {
baseNoise *= pn; baseNoise *= pn;
@ -238,13 +244,13 @@ for (var ix=0; ix<=mapSize; ix++)
// add some higher-frequency noise on land // add some higher-frequency noise on land
if ( oldH > 0 ) 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 // create cliff noise
if ( h > -10 ) 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) if (h < 1)
{ {
var u = 1 - 0.3*((h-1)/-10); var u = 1 - 0.3*((h-1)/-10);
@ -254,7 +260,7 @@ for (var ix=0; ix<=mapSize; ix++)
if (cliffNoise > 0.6) if (cliffNoise > 0.6)
{ {
var u = 0.8 * (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 /= (1 + u);
} }
cliffNoise -= 0.59; cliffNoise -= 0.59;
@ -266,7 +272,7 @@ for (var ix=0; ix<=mapSize; ix++)
} }
// set the height // 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 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 x = ix / (mapSize + 1.0);
var y = iy / (mapSize + 1.0); var z = iz / (mapSize + 1.0);
var pn = playerNearness(x, y); var pn = playerNearness(x, z);
// get heights of surrounding vertices // get heights of surrounding vertices
var h00 = getHeight(ix, iy); var h00 = getHeight(ix, iz);
var h01 = getHeight(ix, iy+1); var h01 = getHeight(ix, iz+1);
var h10 = getHeight(ix+1, iy); var h10 = getHeight(ix+1, iz);
var h11 = getHeight(ix+1, iy+1); var h11 = getHeight(ix+1, iz+1);
// find min and max height // find min and max height
var maxH = Math.max(h00, h01, h10, h11); var maxH = Math.max(h00, h01, h10, h11);
@ -305,12 +311,12 @@ for (var ix=0; ix<mapSize; ix++)
if (maxH > 15) if (maxH > 15)
{ {
var maxNx = min(ix+2, mapSize); 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 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) if (minH < 0)
{ {
addToClass(ix, iy, clWater); addToClass(ix, iz, clWater);
} }
// cliffs // cliffs
if (maxH - minH > 2.9 && minH > -7) if (maxH - minH > 2.9 && minH > -7)
{ {
t = tCliff; t = tCliff;
addToClass(ix, iy, clCliff); addToClass(ix, iz, clCliff);
} }
else if ((maxH - minH > 2.5 && minH > -5) || (maxH-minAdjHeight > 2.9 && minH > 0) ) 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 else
t = [tDirtCliff, tGrassCliff, tGrassCliff, tGrassRock, tCliff]; t = [tDirtCliff, tGrassCliff, tGrassCliff, tGrassRock, tCliff];
addToClass(ix, iy, clCliff); addToClass(ix, iz, clCliff);
} }
// forests // forests
if (maxH - minH < 1 && minH > 1) 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; forestNoise -= 0.59;
if (forestNoise > 0) if (forestNoise > 0)
{ {
if (minH > 5) if (minH > 5)
{ {
var typeNoise = noise10.get(x,y); var typeNoise = noise10.get(x,z);
if (typeNoise < 0.43 && forestNoise < 0.05) if (typeNoise < 0.43 && forestNoise < 0.05)
t = tPoplarForest; t = tPoplarForest;
@ -390,12 +396,12 @@ for (var ix=0; ix<mapSize; ix++)
else else
t = tPineForest; t = tPineForest;
addToClass(ix, iy, clForest); addToClass(ix, iz, clForest);
} }
else if (minH < 3) else if (minH < 3)
{ {
t = tPalmForest; t = tPalmForest;
addToClass(ix, iy, clForest); addToClass(ix, iz, clForest);
} }
} }
} }
@ -403,7 +409,7 @@ for (var ix=0; ix<mapSize; ix++)
// grass variations // grass variations
if (t == tGrass) 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) if (grassNoise < 0.3)
{ {
t = (maxH - minH > 1.2) ? tDirtCliff : tDirt; 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; t = (maxH - minH > 1.2) ? tGrassCliff : tGrassDry;
if (maxH - minH < 0.5 && randFloat() < 0.03) 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) else if (grassNoise > 0.61)
@ -424,12 +430,12 @@ for (var ix=0; ix<mapSize; ix++)
{ {
if ((maxH - minH) < 0.5 && randFloat() < 0.05) 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 // get the x and y in tiles
var fx = fractionToTiles(playerX[i]); var fx = fractionToTiles(playerX[i]);
var fy = fractionToTiles(playerY[i]); var fz = fractionToTiles(playerY[i]);
var ix = round(fx); var ix = round(fx);
var iy = round(fy); var iz = round(fz);
// calculate size based on the radius // calculate size based on the radius
var size = PI * radius * radius; var size = PI * radius * radius;
// create the player area // 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); createArea(placer, paintClass(clPlayer), null);
// create the central road patch // 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); var painter = new TerrainPainter(tDirt);
createArea(placer, painter, null); 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("structures/"+civ+"_civil_centre", 1,1, 0,0),
new SimpleObject("units/"+civ+"_support_female_citizen", 3,3, 5,5) new SimpleObject("units/"+civ+"_support_female_citizen", 3,3, 5,5)
], ],
true, null, ix, iy true, null, ix, iz
); );
createObjectGroup(group, i+1); createObjectGroup(group, i+1);
@ -107,7 +107,7 @@ for (var i=0; i < numPlayers; i++)
var bbAngle = randFloat()*2*PI; var bbAngle = randFloat()*2*PI;
var bbDist = 10; var bbDist = 10;
var bbX = round(fx + bbDist * cos(bbAngle)); var bbX = round(fx + bbDist * cos(bbAngle));
var bbY = round(fy + bbDist * sin(bbAngle)); var bbY = round(fz + bbDist * sin(bbAngle));
group = new SimpleGroup( group = new SimpleGroup(
[new SimpleObject(oSheep, 5,5, 0,2)], [new SimpleObject(oSheep, 5,5, 0,2)],
true, clBaseResource, bbX, bbY true, clBaseResource, bbX, bbY
@ -121,18 +121,18 @@ for (var i=0; i < numPlayers; i++)
} }
var mDist = 12; var mDist = 12;
var mX = round(fx + mDist * cos(mAngle)); var mX = round(fx + mDist * cos(mAngle));
var mY = round(fy + mDist * sin(mAngle)); var mZ = round(fz + mDist * sin(mAngle));
group = new SimpleGroup( group = new SimpleGroup(
[new SimpleObject(oStone, 2,2, 0,3), [new SimpleObject(oStone, 2,2, 0,3),
new SimpleObject(oMetal, 2,2, 0,3)], new SimpleObject(oMetal, 2,2, 0,3)],
true, clBaseResource, mX, mY true, clBaseResource, mX, mZ
); );
createObjectGroup(group, 0); createObjectGroup(group, 0);
// create starting straggler trees // create starting straggler trees
group = new SimpleGroup( group = new SimpleGroup(
[new SimpleObject(oTree, 2,2, 6,12)], [new SimpleObject(oTree, 2,2, 6,12)],
true, null, ix, iy true, null, ix, iz
); );
createObjectGroup(group, 0, avoidClasses(clBaseResource,1)); 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.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() {} function NullConstraint() {}
NullConstraint.prototype.allows = function(x, y) NullConstraint.prototype.allows = function(x, z)
{ {
return true; 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) function AndConstraint(constraints)
{ {
this.constraints = 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) 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; return false;
} }
@ -30,32 +40,48 @@ AndConstraint.prototype.allows = function(x, y)
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// AvoidAreaConstraint // AvoidAreaConstraint
//
// Class representing avoid area constraint
//
// area: Area object, containing points to be avoided
//
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
function AvoidAreaConstraint(area) function AvoidAreaConstraint(area)
{ {
this.area = 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 // AvoidTextureConstraint
//
// Class representing avoid texture constraint
//
// textureID: ID of the texture to be avoided
//
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
function AvoidTextureConstraint(textureID) function AvoidTextureConstraint(textureID)
{ {
this.textureID = 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 // 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) function AvoidTileClassConstraint(tileClassID, distance)
{ {
@ -63,13 +89,19 @@ function AvoidTileClassConstraint(tileClassID, distance)
this.distance = 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 // 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) function StayInTileClassConstraint(tileClassID, distance)
{ {
@ -77,13 +109,20 @@ function StayInTileClassConstraint(tileClassID, distance)
this.distance = 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 // 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) function BorderTileClassConstraint(tileClassID, distanceInside, distanceOutside)
{ {
@ -92,8 +131,8 @@ function BorderTileClassConstraint(tileClassID, distanceInside, distanceOutside)
this.distanceOutside = 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 return (this.tileClass.countMembersInRadius(x, z, this.distanceOutside) > 0
&& this.tileClass.countNonMembersInRadius(x, y, this.distanceInside) > 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 // Get unique ID
this.id = g_Map.getEntityID(); this.id = g_Map.getEntityID();
this.name = name; this.name = name;
// Convert from tile coords to map coords // Tile units
this.x = x; this.tileX = x;
this.y = y; this.tileZ = z;
if (player !== undefined) // Map units (4.0 map units per 1.0 tile)
{ this.x = x * 4.0;
this.player = player; this.y = 0;
this.isActor = false; this.z = z * 4.0;
}
else
{ // Actors have no player ID
this.isActor = true;
}
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 // Set skyset
function setSkySet(set) function setSkySet(set)
@ -40,7 +40,8 @@ function setUnitsAmbientColour(r, g, b)
} }
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Water // Water
////////////////////////////////////////////////////////////////////////////
// Set water colour RGB (0,1) // Set water colour RGB (0,1)
function setWaterColour(r, g, b) function setWaterColour(r, g, b)

View File

@ -9,8 +9,6 @@ const SEA_LEVEL = 20.0;
const TERRAIN_SEPARATOR = "|"; const TERRAIN_SEPARATOR = "|";
const TILES_PER_PATCH = 16;
///////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////
// Utility functions // Utility functions
///////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////
@ -79,14 +77,14 @@ function floor(x)
return Math.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) function println(x)
@ -143,14 +141,14 @@ function createAreas(centeredPlacer, painter, constraint, num, retryFactor)
var r = halfSize * Math.sqrt(randFloat()); // uniform distribution var r = halfSize * Math.sqrt(randFloat()); // uniform distribution
var theta = randFloat(0, 2 * PI); var theta = randFloat(0, 2 * PI);
centeredPlacer.x = Math.floor(r * Math.cos(theta)) + halfSize; 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 else
{ // Rectangular coordinates { // Rectangular coordinates
centeredPlacer.x = randInt(getMapSize()); centeredPlacer.x = randInt(getMapSize());
centeredPlacer.y = randInt(getMapSize()); centeredPlacer.z = randInt(getMapSize());
} }
var area = g_Map.createArea(centeredPlacer, painter, constraint); var area = g_Map.createArea(centeredPlacer, painter, constraint);
if (area !== undefined) if (area !== undefined)
{ {
@ -183,12 +181,12 @@ function createObjectGroups(placer, player, constraint, num, retryFactor)
var r = halfSize * Math.sqrt(randFloat()); // uniform distribution var r = halfSize * Math.sqrt(randFloat()); // uniform distribution
var theta = randFloat(0, 2 * PI); var theta = randFloat(0, 2 * PI);
placer.x = Math.floor(r * Math.cos(theta)) + halfSize; 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 else
{ // Rectangular coordinates { // Rectangular coordinates
placer.x = randInt(getMapSize()); placer.x = randInt(getMapSize());
placer.y = randInt(getMapSize()); placer.z = randInt(getMapSize());
} }
var result = createObjectGroup(placer, player, constraint); 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 // 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; 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 // Add point to given class by id
function addToClass(x, y, id) function addToClass(x, z, id)
{ {
var tileClass = getTileClass(id); var tileClass = getTileClass(id);
if (tileClass !== null) if (tileClass !== null)
{ {
tileClass.add(x, y); tileClass.add(x, z);
} }
} }

View File

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

View File

@ -46,7 +46,7 @@ function InitMap()
// until SpiderMonkey gets upgraded // until SpiderMonkey gets upgraded
g_MapSettings.Size = Math.floor(g_MapSettings.Size); 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); g_Map.initTerrain(terrain);
} }
@ -60,6 +60,9 @@ function ExportMap()
// Add environment and camera settings // Add environment and camera settings
g_Environment.Water.WaterBody.Height = SEA_LEVEL - 0.1; g_Environment.Water.WaterBody.Height = SEA_LEVEL - 0.1;
data.Environment = g_Environment; 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; data.Camera = g_Camera;
RMS.ExportMap(data); RMS.ExportMap(data);

View File

@ -16,6 +16,9 @@ function modPos(num, m)
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
// Noise2D // Noise2D
//
// Class representing 2D noise with a given base frequency
//
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
function Noise2D(freq) function Noise2D(freq)
@ -31,7 +34,7 @@ function Noise2D(freq)
{ {
var a = randFloat() * 2 * PI; 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 // Noise3D
//
// Class representing 3D noise with given base frequencies
//
///////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////
function Noise3D(freq, vfreq) function Noise3D(freq, vfreq)

View File

@ -1,15 +1,21 @@
// Constants for using SmoothElevationPainter
const ELEVATION_SET = 0; const ELEVATION_SET = 0;
const ELEVATION_MODIFY = 1; const ELEVATION_MODIFY = 1;
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// ElevationPainter // ElevationPainter
//
// Class for painting elevation over an area
//
// elevation: Target elevation/height to be painted
//
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
function ElevationPainter(elevation) function ElevationPainter(elevation)
{ {
this.elevation = elevation; this.elevation = elevation;
this.DX = [0, 1, 1, 0]; this.DX = [0, 1, 1, 0];
this.DY = [0, 0, 1, 1]; this.DZ = [0, 0, 1, 1];
} }
ElevationPainter.prototype.paint = function(area) ElevationPainter.prototype.paint = function(area)
@ -23,13 +29,19 @@ ElevationPainter.prototype.paint = function(area)
for (var j=0; j < 4; j++) 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 // 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) function LayeredPainter(terrainArray, widths)
@ -39,7 +51,9 @@ function LayeredPainter(terrainArray, widths)
this.terrains = []; this.terrains = [];
for (var i = 0; i < terrainArray.length; ++i) for (var i = 0; i < terrainArray.length; ++i)
{
this.terrains.push(createTerrain(terrainArray[i])); this.terrains.push(createTerrain(terrainArray[i]));
}
this.widths = widths; this.widths = widths;
} }
@ -63,24 +77,25 @@ LayeredPainter.prototype.paint = function(area)
// push edge points // push edge points
var pts = area.points; var pts = area.points;
var length = pts.length; var length = pts.length;
var areaID = area.getID();
for (var i=0; i < length; i++) for (var i=0; i < length; i++)
{ {
var x = pts[i].x; var x = pts[i].x;
var y = pts[i].y; var z = pts[i].z;
for (var dx=-1; dx <= 1; dx++) for (var dx=-1; dx <= 1; dx++)
{ {
var nx = x+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; saw[nx][nz] = 1;
dist[nx][ny] = 0; dist[nx][nz] = 0;
pointQ.push(new Point(nx, ny)); pointQ.push(new PointXZ(nx, nz));
} }
} }
} }
@ -91,11 +106,11 @@ LayeredPainter.prototype.paint = function(area)
{ {
var pt = pointQ.shift(); // Pop queue var pt = pointQ.shift(); // Pop queue
var px = pt.x; var px = pt.x;
var py = pt.y; var pz = pt.z;
var d = dist[px][py]; var d = dist[px][pz];
// paint if in area // paint if in area
if (g_Map.area[px][py] == area) if (g_Map.area[px][pz] == areaID)
{ {
var w=0; var w=0;
var i=0; var i=0;
@ -108,22 +123,22 @@ LayeredPainter.prototype.paint = function(area)
break; break;
} }
} }
this.terrains[i].place(px, py); this.terrains[i].place(px, pz);
} }
// enqueue neighbours // enqueue neighbours
for (var dx=-1; dx<=1; dx++) for (var dx=-1; dx<=1; dx++)
{ {
var nx = px+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; saw[nx][nz] = 1;
dist[nx][ny] = d+1; dist[nx][nz] = d+1;
pointQ.push(new Point(nx, ny)); pointQ.push(new PointXZ(nx, nz));
} }
} }
} }
@ -132,6 +147,11 @@ LayeredPainter.prototype.paint = function(area)
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// MultiPainter // MultiPainter
//
// Class for applying multiple painters over an area
//
// painters: Array of painter objects
//
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
function MultiPainter(painters) function MultiPainter(painters)
@ -149,6 +169,15 @@ MultiPainter.prototype.paint = function(area)
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// SmoothElevationPainter // 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) function SmoothElevationPainter(type, elevation, blendRadius)
@ -161,16 +190,9 @@ function SmoothElevationPainter(type, elevation, blendRadius)
error("SmoothElevationPainter: invalid type '"+type+"'"); 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.validT(x, z) && g_Map.area[x][z] == areaID);
{
return (g_Map.area[x][y] == area);
}
else
{
return false;
}
}; };
SmoothElevationPainter.prototype.paint = function(area) SmoothElevationPainter.prototype.paint = function(area)
@ -196,25 +218,26 @@ SmoothElevationPainter.prototype.paint = function(area)
} }
var length = pts.length; var length = pts.length;
var areaID = area.getID();
// get a list of all points // get a list of all points
for (var i=0; i < length; i++) for (var i=0; i < length; i++)
{ {
var x = pts[i].x; var x = pts[i].x;
var y = pts[i].y; var z = pts[i].z;
for (var dx=-1; dx <= 2; dx++) for (var dx=-1; dx <= 2; dx++)
{ {
var nx = x+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; gotHeightPt[nx][nz] = 1;
heightPts.push(new Point(nx, ny)); heightPts.push(new PointXZ(nx, nz));
newHeight[nx][ny] = g_Map.height[nx][ny]; newHeight[nx][nz] = g_Map.height[nx][nz];
} }
} }
} }
@ -223,24 +246,25 @@ SmoothElevationPainter.prototype.paint = function(area)
// push edge points // push edge points
for (var i=0; i < length; i++) 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++) for (var dx=-1; dx <= 2; dx++)
{ {
var nx = x+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) if (g_Map.validH(nx, nz)
&& !this.checkInArea(area, nx, ny) && !this.checkInArea(areaID, nx, nz)
&& !this.checkInArea(area, nx-1, ny) && !this.checkInArea(areaID, nx-1, nz)
&& !this.checkInArea(area, nx, ny-1) && !this.checkInArea(areaID, nx, nz-1)
&& !this.checkInArea(area, nx-1, ny-1) && !this.checkInArea(areaID, nx-1, nz-1)
&& !saw[nx][ny]) && !saw[nx][nz])
{ {
saw[nx][ny]= 1; saw[nx][nz]= 1;
dist[nx][ny] = 0; dist[nx][nz] = 0;
pointQ.push(new Point(nx, ny)); pointQ.push(new PointXZ(nx, nz));
} }
} }
} }
@ -251,35 +275,35 @@ SmoothElevationPainter.prototype.paint = function(area)
{ {
var pt = pointQ.shift(); var pt = pointQ.shift();
var px = pt.x; var px = pt.x;
var py = pt.y; var pz = pt.z;
var d = dist[px][py]; var d = dist[px][pz];
// paint if in area // paint if in area
if (g_Map.validH(px, py) if (g_Map.validH(px, pz)
&& (this.checkInArea(area, px, py) || this.checkInArea(area, px-1, py) && (this.checkInArea(areaID, px, pz) || this.checkInArea(areaID, px-1, pz)
|| this.checkInArea(area, px, py-1) || this.checkInArea(area, px-1, py-1))) || this.checkInArea(areaID, px, pz-1) || this.checkInArea(areaID, px-1, pz-1)))
{ {
if (d <= this.blendRadius) if (d <= this.blendRadius)
{ {
var a = (d-1) / this.blendRadius; var a = (d-1) / this.blendRadius;
if (this.type == ELEVATION_SET) 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 else
{ // type == MODIFY { // type == MODIFY
newHeight[px][py] += a*this.elevation; newHeight[px][pz] += a*this.elevation;
} }
} }
else else
{ // also happens when blendRadius == 0 { // also happens when blendRadius == 0
if (this.type == ELEVATION_SET) if (this.type == ELEVATION_SET)
{ {
newHeight[px][py] = this.elevation; newHeight[px][pz] = this.elevation;
} }
else else
{ // type == MODIFY { // 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++) for (var dx=-1; dx <= 1; dx++)
{ {
var nx = px+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)
&& (this.checkInArea(area, nx, ny) || this.checkInArea(area, nx-1, ny) && (this.checkInArea(areaID, nx, nz) || this.checkInArea(areaID, nx-1, nz)
|| this.checkInArea(area, nx, ny-1) || this.checkInArea(area, nx-1, ny-1)) || this.checkInArea(areaID, nx, nz-1) || this.checkInArea(areaID, nx-1, nz-1))
&& !saw[nx][ny]) && !saw[nx][nz])
{ {
saw[nx][ny] = 1; saw[nx][nz] = 1;
dist[nx][ny] = d+1; dist[nx][nz] = d+1;
pointQ.push(new Point(nx, ny)); pointQ.push(new PointXZ(nx, nz));
} }
} }
} }
@ -312,36 +336,41 @@ SmoothElevationPainter.prototype.paint = function(area)
{ {
var pt = heightPts[i]; var pt = heightPts[i];
var px = pt.x; var px = pt.x;
var py = pt.y; var pz = pt.z;
if ((this.checkInArea(area, px, py) || this.checkInArea(area, px-1, py) if ((this.checkInArea(areaID, px, pz) || this.checkInArea(areaID, px-1, pz)
|| this.checkInArea(area, px, py-1) || this.checkInArea(area, px-1, py-1))) || 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; var count = 8;
for (var dx=-1; dx <= 1; dx++) for (var dx=-1; dx <= 1; dx++)
{ {
var nx = px+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++; count++;
} }
} }
} }
g_Map.height[px][py] = sum/count; g_Map.height[px][pz] = sum/count;
} }
} }
}; };
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// TerrainPainter // TerrainPainter
//
// Class for painting a terrain over an area
//
// terrain: Terrain placer object
//
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
function TerrainPainter(terrain) function TerrainPainter(terrain)
@ -355,12 +384,17 @@ TerrainPainter.prototype.paint = function(area)
for (var i=0; i < length; i++) for (var i=0; i < length; i++)
{ {
var pt = area.points[i]; var pt = area.points[i];
this.terrain.place(pt.x, pt.y); this.terrain.place(pt.x, pt.z);
} }
}; };
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// TileClassPainter // TileClassPainter
//
// Class for painting tileClasses over an area
//
// tileClass: TileClass object
//
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
function TileClassPainter(tileClass) function TileClassPainter(tileClass)
@ -374,6 +408,6 @@ TileClassPainter.prototype.paint = function(area)
for (var i=0; i < length; i++) for (var i=0; i < length; i++)
{ {
var pt = area.points[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 // 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.size = size;
this.coherence = coherence; this.coherence = coherence;
this.smoothness = smoothness; this.smoothness = smoothness;
this.failFraction = (failFraction !== undefined ? failFraction : 0); this.failFraction = (failFraction !== undefined ? failFraction : 0);
this.x = (x !== undefined ? x : -1); this.x = (x !== undefined ? x : -1);
this.y = (y !== undefined ? y : -1); this.z = (z !== undefined ? z : -1);
} }
ClumpPlacer.prototype.place = function(constraint) ClumpPlacer.prototype.place = function(constraint)
{ {
// Preliminary bounds check // 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; 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)); var ctrlPts = 1 + Math.floor(1.0/Math.max(this.smoothness,1.0/intPerim));
if (ctrlPts > radius * 2 * PI) 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 noise = new Float32Array(intPerim); //float32
var ctrlCoords = new Float32Array(ctrlPts+1); //float32 var ctrlCoords = new Float32Array(ctrlPts+1); //float32
@ -83,7 +93,7 @@ ClumpPlacer.prototype.place = function(constraint)
var s = sin(th); var s = sin(th);
var c = cos(th); var c = cos(th);
var xx=this.x; var xx=this.x;
var yy=this.y; var yy=this.z;
for (var k=0; k < ceil(r); k++) for (var k=0; k < ceil(r); k++)
{ {
@ -94,7 +104,7 @@ ClumpPlacer.prototype.place = function(constraint)
if (!gotRet[i][j]) if (!gotRet[i][j])
{ // Only include each point once { // Only include each point once
gotRet[i][j] = 1; gotRet[i][j] = 1;
retVec.push(new Point(i, j)); retVec.push(new PointXZ(i, j));
} }
} }
else else
@ -111,24 +121,30 @@ ClumpPlacer.prototype.place = function(constraint)
///////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////
// RectPlacer // 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.x1 = x1;
this.y1 = y1; this.z1 = z1;
this.x2 = x2; 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"); error("RectPlacer: incorrect bounds on rect");
} }
RectPlacer.prototype.place = function(constraint) RectPlacer.prototype.place = function(constraint)
{ {
// Preliminary bounds check // Preliminary bounds check
if (!g_Map.validT(this.x1, this.y1) || !constraint.allows(this.x1, this.y1) || if (!g_Map.validT(this.x1, this.z1) || !constraint.allows(this.x1, this.z1) ||
!g_Map.validT(this.x2, this.y2) || !constraint.allows(this.x2, this.y2)) !g_Map.validT(this.x2, this.z2) || !constraint.allows(this.x2, this.z2))
{ {
return undefined; return undefined;
} }
@ -136,15 +152,15 @@ RectPlacer.prototype.place = function(constraint)
var ret = []; var ret = [];
var x2 = this.x2; var x2 = this.x2;
var y2 = this.y2; var z2 = this.z2;
for (var x=this.x1; x < x2; x++) 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 else
{ {
@ -163,7 +179,15 @@ RectPlacer.prototype.place = function(constraint)
function ObjectGroupPlacer() {} 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) 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"); 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 failCount = 0;
var count = randInt(this.minCount, this.maxCount); 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 direction = randFloat(0, 2*PI);
var x = cx + 0.5 + distance*cos(direction); 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 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; fail = true;
} }
@ -215,7 +239,7 @@ SimpleObject.prototype.place = function(cx, cy, player, avoidSelf, constraint)
for (var i = 0; (i < length) && !fail; i++) for (var i = 0; (i < length) && !fail; i++)
{ {
var dx = x - resultObjs[i].x; var dx = x - resultObjs[i].x;
var dy = y - resultObjs[i].y; var dy = z - resultObjs[i].z;
if ((dx*dx + dy*dy) < 1) if ((dx*dx + dy*dy) < 1)
{ {
@ -226,14 +250,14 @@ SimpleObject.prototype.place = function(cx, cy, player, avoidSelf, constraint)
if (!fail) if (!fail)
{ {
if (!constraint.allows(Math.floor(x), Math.floor(y))) if (!constraint.allows(Math.floor(x), Math.floor(z)))
{ {
fail = true; fail = true;
} }
else else
{ // if we got here, we're good { // if we got here, we're good
var angle = randFloat(this.minAngle, this.maxAngle); 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; break;
} }
} }
@ -253,13 +277,25 @@ SimpleObject.prototype.place = function(cx, cy, player, avoidSelf, constraint)
return resultObjs; 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.elements = elements;
this.tileClass = (tileClass !== undefined ? getTileClass(tileClass) : undefined); this.tileClass = (tileClass !== undefined ? getTileClass(tileClass) : undefined);
this.avoidSelf = (avoidSelf !== undefined ? avoidSelf : false); this.avoidSelf = (avoidSelf !== undefined ? avoidSelf : false);
this.x = (x !== undefined ? x : -1); this.x = (x !== undefined ? x : -1);
this.y = (y !== undefined ? y : -1); this.z = (z !== undefined ? z : -1);
} }
SimpleGroup.prototype.place = function(player, constraint) SimpleGroup.prototype.place = function(player, constraint)
@ -270,7 +306,7 @@ SimpleGroup.prototype.place = function(player, constraint)
var length = this.elements.length; var length = this.elements.length;
for (var i=0; i < length; i++) 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) if (objs === undefined)
{ // Failure { // Failure
return false; return false;
@ -289,7 +325,7 @@ SimpleGroup.prototype.place = function(player, constraint)
if (this.tileClass !== undefined) if (this.tileClass !== undefined)
{ // Round object position to integer { // 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.x = (x !== undefined ? x : 0);
this.y = (y !== undefined ? y : 0); this.y = (y !== undefined ? y : 0);
this.z = (z !== undefined ? z : 0);
} }

View File

@ -1,27 +1,39 @@
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// Terrain // Terrain
//
// Abstract class for terrain placers
//
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
function Terrain() {} function Terrain() {}
Terrain.prototype.place = function(x, y) Terrain.prototype.place = function(x, z)
{ {
// Clear old array // 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() {}; Terrain.prototype.placeNew = function() {};
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// SimpleTerrain // 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) function SimpleTerrain(texture, treeType)
{ {
if (texture === undefined) if (texture === undefined)
{
error("SimpleTerrain: texture not defined"); error("SimpleTerrain: texture not defined");
}
this.texture = texture; this.texture = texture;
this.treeType = treeType; this.treeType = treeType;
@ -29,29 +41,38 @@ function SimpleTerrain(texture, treeType)
SimpleTerrain.prototype = new Terrain(); SimpleTerrain.prototype = new Terrain();
SimpleTerrain.prototype.constructor = SimpleTerrain; SimpleTerrain.prototype.constructor = SimpleTerrain;
SimpleTerrain.prototype.placeNew = function(x, y) SimpleTerrain.prototype.placeNew = function(x, z)
{ {
if (this.treeType !== undefined) 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 // RandomTerrain
//
// Class for placing random SimpleTerrains
//
// terrains: Array of SimpleTerrain objects
//
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
function RandomTerrain(terrains) function RandomTerrain(terrains)
{ {
if (!(terrains instanceof Array) || !terrains.length) if (!(terrains instanceof Array) || !terrains.length)
{
error("Invalid terrains array"); error("Invalid terrains array");
}
this.terrains = terrains; this.terrains = terrains;
} }
RandomTerrain.prototype = new Terrain(); RandomTerrain.prototype = new Terrain();
RandomTerrain.prototype.constructor = RandomTerrain; 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 // RangeOp
//
// Class for efficiently finding number of points within a range
//
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
function RangeOp(size) function RangeOp(size)
@ -60,6 +63,10 @@ RangeOp.prototype.get = function(start, end)
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// TileClass // TileClass
//
// Class for representing terrain types and containing all the tiles
// within that type
//
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
function TileClass(size, id) 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]--; this.inclusionCount[x][z]--;
if(!this.inclusionCount[x][y]) if(!this.inclusionCount[x][z])
{ {
this.rangeCount[y].add(x, -1); this.rangeCount[z].add(x, -1);
} }
}; };

View File

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

View File

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

View File

@ -395,10 +395,10 @@ function init(window)
boxSizer.add(10, 0); boxSizer.add(10, 0);
// TODO: Get this data from single location (currently specified here, Atlas\lists.xml, and game setup) // 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 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 sizeChoice = new wxChoice(rmsPanel, -1, wxDefaultPosition, wxDefaultSize, sizeNames);
var numChoices = sizeNames.length; 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; sizeChoice.selection = 0;
boxSizer.add(sizeChoice, 1); boxSizer.add(sizeChoice, 1);
rmsSizer.add(boxSizer, 0, wxStretch.EXPAND | wxDirection.ALL, 2); rmsSizer.add(boxSizer, 0, wxStretch.EXPAND | wxDirection.ALL, 2);
@ -430,18 +430,14 @@ function init(window)
terrainArray.push(RMSData.BaseTerrain); terrainArray.push(RMSData.BaseTerrain);
} }
// Stringify player data // Complete map settings
var pDataStr = JSON.stringify(Atlas.State.mapSettings.settings.PlayerData); 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 // Generate map
var ret = Atlas.Message.GenerateMap( var ret = Atlas.Message.GenerateMap(RMSData.Script, JSON.stringify(Atlas.State.mapSettings.settings));
RMSData.Script,
sizePatches[sizeChoice.selection],
Atlas.State.Seed ? Atlas.State.Seed : 0,
terrainArray,
RMSData.BaseHeight,
pDataStr
);
// Check for error // Check for error
if (ret.status < 0) if (ret.status < 0)

View File

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

View File

@ -252,9 +252,8 @@ int CMapReader::ApplyData()
{ {
if (m_PatchesPerSide == 0) 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 // 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) if (!only_xml)
@ -1128,7 +1127,7 @@ int CMapReader::ParseTerrain()
{ LOGERROR(L"CMapReader::ParseTerrain() failed to get '%hs' property", #prop);\ { LOGERROR(L"CMapReader::ParseTerrain() failed to get '%hs' property", #prop);\
throw PSERROR_Game_World_MapLoadFailed("Error parsing terrain data.\nCheck application log for details"); } throw PSERROR_Game_World_MapLoadFailed("Error parsing terrain data.\nCheck application log for details"); }
int size; size_t size;
GET_TERRAIN_PROPERTY(size, size) GET_TERRAIN_PROPERTY(size, size)
m_PatchesPerSide = size / PATCH_SIZE; m_PatchesPerSide = size / PATCH_SIZE;
@ -1153,12 +1152,24 @@ int CMapReader::ParseTerrain()
// build tile data // build tile data
m_Tiles.resize(SQR(size)); m_Tiles.resize(SQR(size));
// flat array of tile descriptors
std::vector<CMapIO::STileDesc> tileData; std::vector<CMapIO::STileDesc> tileData;
GET_TERRAIN_PROPERTY(tileData, 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 // reset generator state

View File

@ -970,7 +970,7 @@ bool Autostart(const CmdLineArgs& args)
* -autostart-client -- multiplayer client mode * -autostart-client -- multiplayer client mode
* -autostart-ip=127.0.0.1 -- multiplayer connect to 127.0.0.1 * -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-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: * Examples:
* -autostart=Acropolis -autostart-host -autostart-players=2 -- Host game on Acropolis map, 2 players * -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."); throw PSERROR_Game_World_MapLoadFailed("Error reading random map script.\nCheck application log for details.");
} }
// Get optional map size argument (default 12) // Get optional map size argument (default 192)
uint mapSize = 12; uint mapSize = 192;
if (args.Has("autostart-size")) if (args.Has("autostart-size"))
{ {
CStr size = args.Get("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) if (!JS_ValueToObject(cx, v, &obj) || obj == NULL)
FAIL("Argument must be an object"); 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)) if(!JS_GetProperty(cx, obj, "player", &player) || !FromJSVal(cx, player, out.playerID))
FAIL("Failed to read Entity.isActor property"); FAIL("Failed to read Entity.player 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, "name", &name) || !FromJSVal(cx, name, out.templateName)) if (!JS_GetProperty(cx, obj, "name", &name) || !FromJSVal(cx, name, out.templateName))
FAIL("Failed to read Entity.name property"); FAIL("Failed to read Entity.name property");
if (!JS_GetProperty(cx, obj, "id", &id) || !FromJSVal(cx, id, out.entityID)) if (!JS_GetProperty(cx, obj, "id", &id) || !FromJSVal(cx, id, out.entityID))
FAIL("Failed to read Entity.id property"); FAIL("Failed to read Entity.id property");
if (!JS_GetProperty(cx, obj, "x", &x) || !FromJSVal(cx, x, out.positionX)) if (!JS_GetProperty(cx, obj, "x", &x) || !FromJSVal(cx, x, out.positionX))
FAIL("Failed to read Entity.x property"); FAIL("Failed to read Entity.x property");
if (!JS_GetProperty(cx, obj, "y", &z) || !FromJSVal(cx, z, out.positionZ)) if (!JS_GetProperty(cx, obj, "z", &z) || !FromJSVal(cx, z, out.positionZ))
FAIL("Failed to read Entity.y property"); FAIL("Failed to read Entity.z property");
if (!JS_GetProperty(cx, obj, "orientation", &orient) || !FromJSVal(cx, orient, out.orientationY)) if (!JS_GetProperty(cx, obj, "orientation", &orient) || !FromJSVal(cx, orient, out.orientationY))
FAIL("Failed to read Entity.orientation property"); 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) if (!JS_ValueToObject(cx, v, &obj) || obj == NULL)
FAIL("Argument must be an object"); FAIL("Argument must be an object");
jsval texIdx1, texIdx2, priority; jsval texIdx, priority;
if (!JS_GetProperty(cx, obj, "texIdx1", &texIdx1) || !FromJSVal(cx, texIdx1, out.m_Tex1Index)) if (!JS_GetProperty(cx, obj, "idx", &texIdx) || !FromJSVal(cx, texIdx, out.m_Tex1Index))
FAIL("Failed to read CMapIO::STileDesc.m_Tex1Index property"); 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)) if (!JS_GetProperty(cx, obj, "priority", &priority) || !FromJSVal(cx, priority, out.m_Priority))
FAIL("Failed to read CMapIO::STileDesc.m_Priority property"); 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<int>(JSContext*, int const&);
template jsval ScriptInterface::ToJSVal<float>(JSContext*, float 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<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")); AtObj sizes(Datafile::ReadList("mapsizes"));
for (AtIter s = sizes["size"]; s.defined(); ++s) 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"])); m_SizeArray.Add(wxString(s["@name"]));
size_t patch; size_t size;
std::wstringstream stream; std::wstringstream stream;
stream << (std::wstring)s["@patches"]; stream << (std::wstring)s["@tiles"];
stream >> patch; 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() size_t NewDialog::GetSelectedSize()
{ {
return m_PatchesArray[m_SelectedSize]; return m_TilesArray[m_SelectedSize];
} }
size_t NewDialog::GetBaseHeight() size_t NewDialog::GetBaseHeight()

View File

@ -45,7 +45,7 @@ private:
size_t m_BaseHeight; size_t m_BaseHeight;
wxArrayString m_SizeArray; 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")); wxBusyInfo busy(_("Creating blank map"));
// Generate new blank map // Generate new blank map
size_t patches = dlg.GetSelectedSize(); size_t tiles = dlg.GetSelectedSize();
size_t height = dlg.GetBaseHeight(); size_t height = dlg.GetBaseHeight();
// Get terrain texture // Get terrain texture
// TODO: Support choosing multiple textures // TODO: Support choosing multiple textures
std::vector<std::wstring> textures; std::vector<wxString> textures;
std::wstring baseTexture(g_SelectedTexture.wc_str()); textures.push_back(g_SelectedTexture);
textures.push_back(baseTexture);
// Get player data // TODO: This seems like a nasty way to do this
std::string pData; std::string settings;
m_ScriptInterface.Eval(_T("JSON.stringify(Atlas.State.mapSettings.settings.PlayerData)"), pData); 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 // Generate map
// Script name, size (patches), seed, base terrain(s), base height, player data qGenerateMap qry(L"blank.js", settings);
qGenerateMap qry(L"blank.js", patches, 0, textures, height, pData);
// Wait for map generation to finish // Wait for map generation to finish
qry.Post(); qry.Post();

View File

@ -79,22 +79,12 @@ QUERYHANDLER(GenerateMap)
// Random map // Random map
ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface(); ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface();
CScriptValRooted settings = scriptInterface.ParseJSON(*msg->settings);
CScriptValRooted attrs; CScriptValRooted attrs;
scriptInterface.Eval("({})", attrs); scriptInterface.Eval("({})", attrs);
scriptInterface.SetProperty(attrs.get(), "mapType", std::string("random")); scriptInterface.SetProperty(attrs.get(), "mapType", std::string("random"));
scriptInterface.SetProperty(attrs.get(), "script", std::wstring(*msg->script)); scriptInterface.SetProperty(attrs.get(), "script", std::wstring(*msg->filename));
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(), "settings", settings, false); scriptInterface.SetProperty(attrs.get(), "settings", settings, false);
try try

View File

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