mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-06-21 14:43:52 +00:00
Change placeObject, placeStartingWalls, wall builder library and wall demo to use vectors, refs #4845, #4992.
This was SVN commit r21021.
This commit is contained in:
@@ -267,7 +267,7 @@ for (var ix = 0; ix < mapSize; ix++)
|
||||
|
||||
if (h > 35 && randBool(0.1) ||
|
||||
h < 15 && randBool(0.05) && hillDecoClass.countMembersInRadius(ix, iz, 1) == 0)
|
||||
placeObject(ix + randFloat(0, 1), iz + randFloat(0, 1), pickRandom(aTrees), 0, randomAngle());
|
||||
placeObject(Vector2D.add(position, new Vector2D(1, 1).mult(randFloat(0, 1))), pickRandom(aTrees), 0, randomAngle());
|
||||
}
|
||||
|
||||
var explorableArea = g_Map.createArea(explorablePoints);
|
||||
|
||||
@@ -259,7 +259,6 @@ else if (mapSize > 400)
|
||||
propDensity = 3/4;
|
||||
|
||||
for(var x = minTerrainDistToBorder; x < mapSize - minTerrainDistToBorder; x++)
|
||||
{
|
||||
for (var y = minTerrainDistToBorder; y < mapSize - minTerrainDistToBorder; y++)
|
||||
{
|
||||
let position = new Vector2D(x, y);
|
||||
@@ -270,109 +269,113 @@ for(var x = minTerrainDistToBorder; x < mapSize - minTerrainDistToBorder; x++)
|
||||
{
|
||||
createTerrain(textueByHeight[i].terrain).place(position);
|
||||
|
||||
// Add some props at...
|
||||
let template;
|
||||
|
||||
if (i == 0) // ...deep water
|
||||
{
|
||||
if (randBool(propDensity / 100))
|
||||
placeObject(x, y, "actor|props/flora/pond_lillies_large.xml", 0, randomAngle());
|
||||
template = "actor|props/flora/pond_lillies_large.xml";
|
||||
else if (randBool(propDensity / 40))
|
||||
placeObject(x, y, "actor|props/flora/water_lillies.xml", 0, randomAngle());
|
||||
template = "actor|props/flora/water_lillies.xml";
|
||||
}
|
||||
if (i == 1) // ...medium water (with fish)
|
||||
{
|
||||
if (randBool(propDensity / 200))
|
||||
placeObject(x, y, "actor|props/flora/pond_lillies_large.xml", 0, randomAngle());
|
||||
template = "actor|props/flora/pond_lillies_large.xml";
|
||||
else if (randBool(propDensity / 100))
|
||||
placeObject(x, y, "actor|props/flora/water_lillies.xml", 0, randomAngle());
|
||||
template = "actor|props/flora/water_lillies.xml";
|
||||
}
|
||||
if (i == 2) // ...low water/mud
|
||||
{
|
||||
if (randBool(propDensity / 200))
|
||||
placeObject(x, y, "actor|props/flora/water_log.xml", 0, randomAngle());
|
||||
template = "actor|props/flora/water_log.xml";
|
||||
else if (randBool(propDensity / 100))
|
||||
placeObject(x, y, "actor|props/flora/water_lillies.xml", 0, randomAngle());
|
||||
template = "actor|props/flora/water_lillies.xml";
|
||||
else if (randBool(propDensity / 40))
|
||||
placeObject(x, y, "actor|geology/highland_c.xml", 0, randomAngle());
|
||||
template = "actor|geology/highland_c.xml";
|
||||
else if (randBool(propDensity / 20))
|
||||
placeObject(x, y, "actor|props/flora/reeds_pond_lush_b.xml", 0, randomAngle());
|
||||
template = "actor|props/flora/reeds_pond_lush_b.xml";
|
||||
else if (randBool(propDensity / 10))
|
||||
placeObject(x, y, "actor|props/flora/reeds_pond_lush_a.xml", 0, randomAngle());
|
||||
template = "actor|props/flora/reeds_pond_lush_a.xml";
|
||||
}
|
||||
if (i == 3) // ...water suroundings/bog
|
||||
{
|
||||
if (randBool(propDensity / 200))
|
||||
placeObject(x, y, "actor|props/flora/water_log.xml", 0, randomAngle());
|
||||
template = "actor|props/flora/water_log.xml";
|
||||
else if (randBool(propDensity / 100))
|
||||
placeObject(x, y, "actor|geology/highland_c.xml", 0, randomAngle());
|
||||
template = "actor|geology/highland_c.xml";
|
||||
else if (randBool(propDensity / 40))
|
||||
placeObject(x, y, "actor|props/flora/reeds_pond_lush_a.xml", 0, randomAngle());
|
||||
template = "actor|props/flora/reeds_pond_lush_a.xml";
|
||||
}
|
||||
if (i == 4) // ...low height grass
|
||||
{
|
||||
if (randBool(propDensity / 800))
|
||||
placeObject(x, y, "actor|props/flora/grass_field_flowering_tall.xml", 0, randomAngle());
|
||||
template = "actor|props/flora/grass_field_flowering_tall.xml";
|
||||
else if (randBool(propDensity / 400))
|
||||
placeObject(x, y, "actor|geology/gray_rock1.xml", 0, randomAngle());
|
||||
template = "actor|geology/gray_rock1.xml";
|
||||
else if (randBool(propDensity / 200))
|
||||
placeObject(x, y, "actor|props/flora/bush_tempe_sm_lush.xml", 0, randomAngle());
|
||||
template = "actor|props/flora/bush_tempe_sm_lush.xml";
|
||||
else if (randBool(propDensity / 100))
|
||||
placeObject(x, y, "actor|props/flora/bush_tempe_b.xml", 0, randomAngle());
|
||||
template = "actor|props/flora/bush_tempe_b.xml";
|
||||
else if (randBool(propDensity / 40))
|
||||
placeObject(x, y, "actor|props/flora/grass_soft_small_tall.xml", 0, randomAngle());
|
||||
template = "actor|props/flora/grass_soft_small_tall.xml";
|
||||
}
|
||||
if (i == 5) // ...medium height grass
|
||||
{
|
||||
if (randBool(propDensity / 800))
|
||||
placeObject(x, y, "actor|geology/decal_stone_medit_a.xml", 0, randomAngle());
|
||||
template = "actor|geology/decal_stone_medit_a.xml";
|
||||
else if (randBool(propDensity / 400))
|
||||
placeObject(x, y, "actor|props/flora/decals_flowers_daisies.xml", 0, randomAngle());
|
||||
template = "actor|props/flora/decals_flowers_daisies.xml";
|
||||
else if (randBool(propDensity / 200))
|
||||
placeObject(x, y, "actor|props/flora/bush_tempe_underbrush.xml", 0, randomAngle());
|
||||
template = "actor|props/flora/bush_tempe_underbrush.xml";
|
||||
else if (randBool(propDensity / 100))
|
||||
placeObject(x, y, "actor|props/flora/grass_soft_small_tall.xml", 0, randomAngle());
|
||||
template = "actor|props/flora/grass_soft_small_tall.xml";
|
||||
else if (randBool(propDensity / 40))
|
||||
placeObject(x, y, "actor|props/flora/grass_temp_field.xml", 0, randomAngle());
|
||||
template = "actor|props/flora/grass_temp_field.xml";
|
||||
}
|
||||
if (i == 6) // ...high height grass
|
||||
{
|
||||
if (randBool(propDensity / 400))
|
||||
placeObject(x, y, "actor|geology/stone_granite_boulder.xml", 0, randomAngle());
|
||||
template = "actor|geology/stone_granite_boulder.xml";
|
||||
else if (randBool(propDensity / 200))
|
||||
placeObject(x, y, "actor|props/flora/foliagebush.xml", 0, randomAngle());
|
||||
template = "actor|props/flora/foliagebush.xml";
|
||||
else if (randBool(propDensity / 100))
|
||||
placeObject(x, y, "actor|props/flora/bush_tempe_underbrush.xml", 0, randomAngle());
|
||||
template = "actor|props/flora/bush_tempe_underbrush.xml";
|
||||
else if (randBool(propDensity / 40))
|
||||
placeObject(x, y, "actor|props/flora/grass_soft_small_tall.xml", 0, randomAngle());
|
||||
template = "actor|props/flora/grass_soft_small_tall.xml";
|
||||
else if (randBool(propDensity / 20))
|
||||
placeObject(x, y, "actor|props/flora/ferns.xml", 0, randomAngle());
|
||||
template = "actor|props/flora/ferns.xml";
|
||||
}
|
||||
if (i == 7) // ...forest border (with wood/food plants/deer/rabits)
|
||||
{
|
||||
if (randBool(propDensity / 400))
|
||||
placeObject(x, y, "actor|geology/highland_c.xml", 0, randomAngle());
|
||||
template = "actor|geology/highland_c.xml";
|
||||
else if (randBool(propDensity / 200))
|
||||
placeObject(x, y, "actor|props/flora/bush_tempe_a.xml", 0, randomAngle());
|
||||
template = "actor|props/flora/bush_tempe_a.xml";
|
||||
else if (randBool(propDensity / 100))
|
||||
placeObject(x, y, "actor|props/flora/ferns.xml", 0, randomAngle());
|
||||
template = "actor|props/flora/ferns.xml";
|
||||
else if (randBool(propDensity / 40))
|
||||
placeObject(x, y, "actor|props/flora/grass_soft_tuft_a.xml", 0, randomAngle());
|
||||
template = "actor|props/flora/grass_soft_tuft_a.xml";
|
||||
}
|
||||
if (i == 8) // ...woods
|
||||
{
|
||||
if (randBool(propDensity / 200))
|
||||
placeObject(x, y, "actor|geology/highland2_moss.xml", 0, randomAngle());
|
||||
template = "actor|geology/highland2_moss.xml";
|
||||
else if (randBool(propDensity / 100))
|
||||
placeObject(x, y, "actor|props/flora/grass_soft_tuft_a.xml", 0, randomAngle());
|
||||
template = "actor|props/flora/grass_soft_tuft_a.xml";
|
||||
else if (randBool(propDensity / 40))
|
||||
placeObject(x, y, "actor|props/flora/ferns.xml", 0, randomAngle());
|
||||
template = "actor|props/flora/ferns.xml";
|
||||
}
|
||||
|
||||
if (template)
|
||||
placeObject(position, template, 0, randomAngle());
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
textureMinHeight = textueByHeight[i].upperHeightLimit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Engine.SetProgress(90);
|
||||
|
||||
@@ -404,7 +407,7 @@ else
|
||||
new Vector2D(-0.75 * resourceSpacing * Math.floor(resourceCount / 2), 0).rotate(-uAngle - Math.PI/2)
|
||||
]);
|
||||
|
||||
placeObject(pos.x, pos.y, j % 2 ? "gaia/flora_tree_cypress" : "gaia/flora_bush_berry", 0, randomAngle());
|
||||
placeObject(pos, j % 2 ? "gaia/flora_tree_cypress" : "gaia/flora_bush_berry", 0, randomAngle());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,15 +53,16 @@ let decorations = [
|
||||
|
||||
function placeMine(point, centerEntity)
|
||||
{
|
||||
placeObject(point.x, point.y, centerEntity, 0, randomAngle());
|
||||
placeObject(point, centerEntity, 0, randomAngle());
|
||||
let quantity = randIntInclusive(11, 23);
|
||||
let dAngle = 2 * Math.PI / quantity;
|
||||
|
||||
for (let i = 0; i < quantity; ++i)
|
||||
{
|
||||
let angle = dAngle * randFloat(i, i + 1);
|
||||
let dist = randFloat(2, 5);
|
||||
placeObject(point.x + dist * Math.cos(angle), point.y + dist * Math.sin(angle), pickRandom(decorations), 0, randomAngle());
|
||||
}
|
||||
placeObject(
|
||||
Vector2D.add(point, new Vector2D(randFloat(2, 5), 0).rotate(-dAngle * randFloat(i, i + 1))),
|
||||
pickRandom(decorations),
|
||||
0,
|
||||
randomAngle());
|
||||
}
|
||||
|
||||
// Food, fences with domestic animals
|
||||
@@ -122,7 +123,7 @@ let clGrove = g_Map.createTileClass();
|
||||
|
||||
function placeGrove(point)
|
||||
{
|
||||
placeObject(point.x, point.y, pickRandom(["structures/gaul_outpost", "gaia/flora_tree_oak_new"]), 0, randomAngle());
|
||||
placeObject(point, pickRandom(["structures/gaul_outpost", "gaia/flora_tree_oak_new"]), 0, randomAngle());
|
||||
let quantity = randIntInclusive(20, 30);
|
||||
let dAngle = 2 * Math.PI / quantity;
|
||||
for (let i = 0; i < quantity; ++i)
|
||||
@@ -133,7 +134,7 @@ function placeGrove(point)
|
||||
if (i % 3 == 0)
|
||||
objectList = groveActors;
|
||||
let position = Vector2D.add(point, new Vector2D(dist, 0).rotate(-angle));
|
||||
placeObject(position.x, position.y, pickRandom(objectList), 0, randomAngle());
|
||||
placeObject(position, pickRandom(objectList), 0, randomAngle());
|
||||
createArea(
|
||||
new ClumpPlacer(5, 1, 1, 1, position),
|
||||
[
|
||||
@@ -152,14 +153,14 @@ function placeCamp(point,
|
||||
]
|
||||
)
|
||||
{
|
||||
placeObject(point.x, point.y, centerEntity, 0, randomAngle());
|
||||
placeObject(point, centerEntity, 0, randomAngle());
|
||||
let quantity = randIntInclusive(5, 11);
|
||||
let dAngle = 2 * Math.PI / quantity;
|
||||
for (let i = 0; i < quantity; ++i)
|
||||
{
|
||||
let angle = dAngle * randFloat(i, i + 1);
|
||||
let dist = randFloat(1, 3);
|
||||
placeObject(point.x + dist * Math.cos(angle), point.y + dist * Math.sin(angle), pickRandom(otherEntities), 0, randomAngle());
|
||||
placeObject(Vector2D.add(point, new Vector2D(dist, 0).rotate(-angle)), pickRandom(otherEntities), 0, randomAngle());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +185,7 @@ function placeStartLocationResources(point, foodEntities = ["gaia/flora_bush_ber
|
||||
if (i % 2 == 0)
|
||||
objectList = groveActors;
|
||||
let woodPosition = Vector2D.add(point, new Vector2D(randFloat(10, 15), 0).rotate(-angle));
|
||||
placeObject(woodPosition.x, woodPosition.y, pickRandom(objectList), 0, randomAngle());
|
||||
placeObject(woodPosition, pickRandom(objectList), 0, randomAngle());
|
||||
createArea(
|
||||
new ClumpPlacer(5, 1, 1, 1, woodPosition),
|
||||
[
|
||||
@@ -208,7 +209,7 @@ function placeStartLocationResources(point, foodEntities = ["gaia/flora_bush_ber
|
||||
{
|
||||
angle = currentAngle + randFloat(0, dAngle);
|
||||
let berriesPosition = Vector2D.add(point, new Vector2D(randFloat(10, 15), 0).rotate(-angle));
|
||||
placeObject(berriesPosition.x, berriesPosition.y, pickRandom(foodEntities), 0, randomAngle());
|
||||
placeObject(berriesPosition, pickRandom(foodEntities), 0, randomAngle());
|
||||
currentAngle += dAngle;
|
||||
}
|
||||
}
|
||||
@@ -413,7 +414,7 @@ for (let h = 0; h < heighLimits.length; ++h)
|
||||
g_Map.setTexture(point, texture);
|
||||
|
||||
if (actor)
|
||||
placeObject(point.x + randFloat(0, 1), point.y + randFloat(0, 1), actor, 0, randomAngle());
|
||||
placeObject(Vector2D.add(point, new Vector2D(randFloat(0, 1), randFloat(0, 1))), actor, 0, randomAngle());
|
||||
}
|
||||
Engine.SetProgress(80);
|
||||
|
||||
@@ -423,25 +424,26 @@ if (isNomad())
|
||||
else
|
||||
for (let p = 0; p < playerIDs.length; ++p)
|
||||
{
|
||||
let point = startLocations[p];
|
||||
placeCivDefaultStartingEntities(point, playerIDs[p], true);
|
||||
placeStartLocationResources(startLocations[p]);
|
||||
let pos = new Vector2D(startLocations[p].x, startLocations[p].y);
|
||||
placeCivDefaultStartingEntities(pos, playerIDs[p], true);
|
||||
placeStartLocationResources(pos);
|
||||
}
|
||||
|
||||
log("Placing resources, farmsteads, groves and camps...");
|
||||
for (let i = 0; i < resourceSpots.length; ++i)
|
||||
{
|
||||
let pos = new Vector2D(resourceSpots[i].x, resourceSpots[i].y);
|
||||
let choice = i % 5;
|
||||
if (choice == 0)
|
||||
placeMine(resourceSpots[i], "gaia/geology_stonemine_temperate_formation");
|
||||
placeMine(pos, "gaia/geology_stonemine_temperate_formation");
|
||||
if (choice == 1)
|
||||
placeMine(resourceSpots[i], "gaia/geology_metal_temperate_slabs");
|
||||
placeMine(pos, "gaia/geology_metal_temperate_slabs");
|
||||
if (choice == 2)
|
||||
placeCustomFortress(resourceSpots[i].x, resourceSpots[i].y, pickRandom(fences), "other", 0, randomAngle());
|
||||
placeCustomFortress(pos, pickRandom(fences), "other", 0, randomAngle());
|
||||
if (choice == 3)
|
||||
placeGrove(resourceSpots[i]);
|
||||
placeGrove(pos);
|
||||
if (choice == 4)
|
||||
placeCamp(resourceSpots[i]);
|
||||
placeCamp(pos);
|
||||
}
|
||||
|
||||
g_Map.ExportMap();
|
||||
|
||||
@@ -338,7 +338,7 @@ createStragglerTrees(
|
||||
log("Creating treasures...");
|
||||
for (let i = 0; i < randIntInclusive(3, 8); ++i)
|
||||
for (let template of [oFoodTreasure, oWoodTreasure])
|
||||
placeObject(mapCenter.x + randFloat(-7, 7), mapCenter.y + randFloat(-7, 7), template, 0, randomAngle());
|
||||
placeObject(Vector2D.add(mapCenter, new Vector2D(randFloat(0, 7), 0).rotate(randomAngle())), template, 0, randomAngle());
|
||||
|
||||
placePlayersNomad(
|
||||
clPlayer,
|
||||
|
||||
@@ -298,17 +298,17 @@ if (gallicCC)
|
||||
new TileClassPainter(clRitualPlace)
|
||||
]);
|
||||
|
||||
placeObject(meetingPlacePosition.x, meetingPlacePosition.y, aCampfire, 0, randomAngle());
|
||||
placeObject(meetingPlacePosition, aCampfire, 0, randomAngle());
|
||||
|
||||
for (let participants of ritualParticipants)
|
||||
{
|
||||
let [positions, angles] = distributePointsOnCircle(participants.count, startAngle, participants.radius * mRadius, meetingPlacePosition);
|
||||
for (let i = 0; i < positions.length; ++i)
|
||||
placeObject(positions[i].x, positions[i].y, pickRandom(participants.templates), 0, angles[i] + participants.angle);
|
||||
placeObject(positions[i], pickRandom(participants.templates), 0, angles[i] + participants.angle);
|
||||
}
|
||||
}
|
||||
|
||||
placeObject(civicCenterPosition.x, civicCenterPosition.y, oCivicCenter, 0, startAngle + BUILDING_ORIENTATION + Math.PI * 3/2 * i);
|
||||
placeObject(civicCenterPosition, oCivicCenter, 0, startAngle + BUILDING_ORIENTATION + Math.PI * 3/2 * i);
|
||||
|
||||
// Create the city patch
|
||||
createArea(
|
||||
@@ -319,14 +319,13 @@ if (gallicCC)
|
||||
]);
|
||||
|
||||
// Place walls and buildings
|
||||
placeCustomFortress(civicCenterPosition.x, civicCenterPosition.y, fortressDanubiusVillage, "danubius_village", 0, startAngle + Math.PI);
|
||||
placeCustomFortress(civicCenterPosition.x, civicCenterPosition.y, fortressDanubiusSpikes, "danubius_spikes", 0, startAngle + Math.PI);
|
||||
placeCustomFortress(civicCenterPosition, fortressDanubiusVillage, "danubius_village", 0, startAngle + Math.PI);
|
||||
placeCustomFortress(civicCenterPosition, fortressDanubiusSpikes, "danubius_spikes", 0, startAngle + Math.PI);
|
||||
|
||||
// Place treasure, potentially inside buildings
|
||||
for (let i = 0; i < gallicCCTreasureCount; ++i)
|
||||
placeObject(
|
||||
civicCenterPosition.x + randFloat(-0.8, 0.8) * gaulCityRadius,
|
||||
civicCenterPosition.y + randFloat(-0.8, 0.8) * gaulCityRadius,
|
||||
Vector2D.add(civicCenterPosition, new Vector2D(randFloat(-1, 1) * 0.8 * gaulCityRadius, 0).rotate(randomAngle())),
|
||||
pickRandom(oTreasures),
|
||||
0,
|
||||
randomAngle());
|
||||
@@ -715,8 +714,8 @@ for (let i = 0; i < 2; ++i)
|
||||
log("Creating patrol points for land attackers...");
|
||||
addToClass(mapCenter.x, mapCenter.y, clMiddle);
|
||||
|
||||
var riverDirectionPosition = Vector2D.add(mapCenter, new Vector2D(0, 1).rotate(startAngle));
|
||||
placeObject(riverDirectionPosition.x, riverDirectionPosition.y, triggerPointRiverDirection, 0, 0);
|
||||
log("Creating triggerpoint to allow the triggerscript to determine the river direction...");
|
||||
placeObject(Vector2D.add(mapCenter, new Vector2D(0, 1).rotate(startAngle)), triggerPointRiverDirection, 0, 0);
|
||||
|
||||
for (let i = 0; i < 2; ++i)
|
||||
{
|
||||
|
||||
@@ -134,7 +134,7 @@ for (let i = 0; i < numPlayers; ++i)
|
||||
let angle = playerAngle[i] + angleDist * (rIndex + 1) / (resourcePerPlayer.length + 1);
|
||||
let position = Vector2D.add(mapCenter, new Vector2D(resourceRadius, 0).rotate(-angle)).round();
|
||||
|
||||
placeObject(position.x, position.y, resourcePerPlayer[rIndex], 0, randomAngle());
|
||||
placeObject(position, resourcePerPlayer[rIndex], 0, randomAngle());
|
||||
|
||||
createArea(
|
||||
new ClumpPlacer(40, 1/2, 1/8, 1, position),
|
||||
@@ -147,7 +147,7 @@ for (let i = 0; i < numPlayers; ++i)
|
||||
Engine.SetProgress(60);
|
||||
|
||||
log("Placing temple...");
|
||||
placeObject(mapCenter.x, mapCenter.y, templateTemple, 0, randomAngle());
|
||||
placeObject(mapCenter, templateTemple, 0, randomAngle());
|
||||
addToClass(mapCenter.x, mapCenter.y, clBaseResource);
|
||||
|
||||
log("Creating central mountain...");
|
||||
|
||||
@@ -132,7 +132,7 @@ for (let i = 0; i < numPlayers; ++i)
|
||||
"cornerIn", "long", "house", "tower", "long", "tower", "long",
|
||||
"cornerIn", "long", "house", "tower"];
|
||||
}
|
||||
placeCustomFortress(playerPosition[i].x, playerPosition[i].y, new Fortress("Spahbod", wall), civ, playerIDs[i], -Math.PI/4);
|
||||
placeCustomFortress(playerPosition[i], new Fortress("Spahbod", wall), civ, playerIDs[i], -Math.PI/4);
|
||||
}
|
||||
|
||||
log("Creating lakes...");
|
||||
|
||||
@@ -84,7 +84,7 @@ if (!isNomad())
|
||||
]);
|
||||
|
||||
let dockLocation = findLocationInDirectionBasedOnHeight(playerPosition[i], mapCenter, -3 , heightLand - 0.5, heightLand);
|
||||
placeObject(dockLocation.x, dockLocation.y, oDock, playerIDs[i], playerAngle[i] + Math.PI);
|
||||
placeObject(dockLocation, oDock, playerIDs[i], playerAngle[i] + Math.PI);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -304,14 +304,14 @@ for (var ix = 0; ix < mapSize; ix++)
|
||||
{
|
||||
t = (diffH > 1.2) ? tGrassCliff : tGrassDry;
|
||||
if (diffH < 0.5 && randBool(0.02))
|
||||
placeObject(randFloat(ix, ix + 1), randFloat(iz, iz + 1), aGrassDry, 0, randomAngle());
|
||||
placeObject(Vector2D.add(position, new Vector2D(1, 1).mult(randFloat(0, 1))), aGrassDry, 0, randomAngle());
|
||||
}
|
||||
else if (grassNoise > 0.61)
|
||||
{
|
||||
t = (diffH > 1.2 ? tGrassRock : tGrassShrubs);
|
||||
}
|
||||
else if (diffH < 0.5 && randBool(0.02))
|
||||
placeObject(randFloat(ix, ix + 1), randFloat(iz, iz + 1), aGrass, 0, randomAngle());
|
||||
placeObject(Vector2D.add(position, new Vector2D(1, 1).mult(randFloat(0, 1))), aGrass, 0, randomAngle());
|
||||
}
|
||||
|
||||
createTerrain(t).place(position);
|
||||
|
||||
@@ -87,7 +87,7 @@ for (let i = 0; i < numPlayers; ++i)
|
||||
continue;
|
||||
|
||||
let dockLocation = findLocationInDirectionBasedOnHeight(playerPosition[i], mapCenter, -3 , 2.6, 3);
|
||||
placeObject(dockLocation.x, dockLocation.y, oDock, playerIDs[i], playerAngle[i] + Math.PI);
|
||||
placeObject(dockLocation, oDock, playerIDs[i], playerAngle[i] + Math.PI);
|
||||
}
|
||||
Engine.SetProgress(10);
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ if (!isNomad())
|
||||
for (let i = 0; i < numPlayers; ++i)
|
||||
{
|
||||
let marketPos = Vector2D.add(playerPosition[i], new Vector2D(12, 0).rotate(randomAngle())).round();
|
||||
placeObject(marketPos.x, marketPos.y, oMarket, playerIDs[i], BUILDING_ORIENTATION);
|
||||
placeObject(marketPos, oMarket, playerIDs[i], BUILDING_ORIENTATION);
|
||||
addCivicCenterAreaToClass(marketPos, clBaseResource);
|
||||
}
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ function createStoneMineFormation(position, templateName, terrain, radius = 2.5,
|
||||
for (let i = 0; i < count; ++i)
|
||||
{
|
||||
let pos = Vector2D.add(position, new Vector2D(radius + randFloat(0, maxOffset), 0).rotate(-angle)).round();
|
||||
placeObject(pos.x, pos.y, templateName, 0, randomAngle());
|
||||
placeObject(pos, templateName, 0, randomAngle());
|
||||
angle += 3/2 * Math.PI / count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,11 +183,10 @@ function createTerrain(terrain)
|
||||
new RandomTerrain(terrain.map(t => createTerrain(t)));
|
||||
}
|
||||
|
||||
function placeObject(x, z, type, player, angle)
|
||||
function placeObject(position, type, player, angle)
|
||||
{
|
||||
let position = new Vector2D(x, z);
|
||||
if (g_Map.validTile(position))
|
||||
g_Map.addObject(new Entity(type, player, x, z, angle));
|
||||
g_Map.addObject(new Entity(type, player, position.x, position.y, angle));
|
||||
}
|
||||
|
||||
function getTileClass(id)
|
||||
|
||||
@@ -79,7 +79,7 @@ function placeStartingEntities(location, playerID, civEntities, dist = 6, orient
|
||||
let firstTemplate = civEntities[i].Template;
|
||||
if (firstTemplate.startsWith("structures/"))
|
||||
{
|
||||
placeObject(location.x, location.y, firstTemplate, playerID, orientation);
|
||||
placeObject(location, firstTemplate, playerID, orientation);
|
||||
++i;
|
||||
}
|
||||
|
||||
@@ -91,38 +91,41 @@ function placeStartingEntities(location, playerID, civEntities, dist = 6, orient
|
||||
let count = civEntities[j].Count || 1;
|
||||
|
||||
for (let num = 0; num < count; ++num)
|
||||
placeObject(
|
||||
location.x + dist * Math.cos(angle) + space * (-num + 0.75 * Math.floor(count / 2)) * Math.sin(angle),
|
||||
location.y + dist * Math.sin(angle) + space * (num - 0.75 * Math.floor(count / 2)) * Math.cos(angle),
|
||||
civEntities[j].Template,
|
||||
playerID,
|
||||
angle);
|
||||
{
|
||||
let position = Vector2D.sum([
|
||||
location,
|
||||
new Vector2D(dist, 0).rotate(-angle),
|
||||
new Vector2D(space * (-num + 0.75 * Math.floor(count / 2)), 0).rotate(angle)
|
||||
]);
|
||||
|
||||
placeObject(position, civEntities[j].Template, playerID, angle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Places the default starting entities as defined by the civilization definition, optionally including city walls.
|
||||
*/
|
||||
function placeCivDefaultStartingEntities(location, playerID, wallType, dist = 6, orientation = BUILDING_ORIENTATION)
|
||||
function placeCivDefaultStartingEntities(position, playerID, wallType, dist = 6, orientation = BUILDING_ORIENTATION)
|
||||
{
|
||||
placeStartingEntities(location, playerID, getStartingEntities(playerID), dist, orientation);
|
||||
placeStartingWalls(location.x, location.y, playerID, wallType, orientation);
|
||||
placeStartingEntities(position, playerID, getStartingEntities(playerID), dist, orientation);
|
||||
placeStartingWalls(position, playerID, wallType, orientation);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the map is large enough and the civilization defines them, places the initial city walls or towers.
|
||||
* @param {string|boolean} wallType - Either "towers" to only place the wall turrets or a boolean indicating enclosing city walls.
|
||||
*/
|
||||
function placeStartingWalls(x, z, playerID, wallType, orientation = BUILDING_ORIENTATION)
|
||||
function placeStartingWalls(position, playerID, wallType, orientation = BUILDING_ORIENTATION)
|
||||
{
|
||||
let civ = getCivCode(playerID);
|
||||
if (civ != "iber" || g_Map.getSize() <= 128)
|
||||
return;
|
||||
|
||||
if (wallType == "towers")
|
||||
placePolygonalWall(x, z, 15, ["entry"], "tower", civ, playerID, orientation, 7);
|
||||
placePolygonalWall(position, 15, ["entry"], "tower", civ, playerID, orientation, 7);
|
||||
else if (wallType)
|
||||
placeGenericFortress(x, z, 20, playerID);
|
||||
placeGenericFortress(position, 20, playerID);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -279,19 +279,17 @@ function readyWallElement(path, civCode)
|
||||
* Placing the first wall element at startX/startY placed with an angle given by orientation
|
||||
* An alignment can be used to get the "center" of a "wall" (more likely used for fortresses) with getCenterToFirstElement
|
||||
*
|
||||
* @param {number} startX
|
||||
* @param {number} startY
|
||||
* @param {Vector2D} position
|
||||
* @param {array} [wall]
|
||||
* @param {string} [style]
|
||||
* @param {number} [orientation]
|
||||
* @returns {array}
|
||||
*/
|
||||
function getWallAlignment(startX, startY, wall = [], style = "athen_stone", orientation = 0)
|
||||
function getWallAlignment(position, wall = [], style = "athen_stone", orientation = 0)
|
||||
{
|
||||
style = validateStyle(style);
|
||||
let alignment = [];
|
||||
let wallX = startX;
|
||||
let wallY = startY;
|
||||
let wallPosition = position.clone();
|
||||
|
||||
for (let i = 0; i < wall.length; ++i)
|
||||
{
|
||||
@@ -302,14 +300,9 @@ function getWallAlignment(startX, startY, wall = [], style = "athen_stone", orie
|
||||
continue;
|
||||
}
|
||||
|
||||
// Indentation
|
||||
let placeX = wallX - element.indent * Math.cos(orientation);
|
||||
let placeY = wallY - element.indent * Math.sin(orientation);
|
||||
|
||||
// Add wall elements entity placement arguments to the alignment
|
||||
alignment.push({
|
||||
"x": placeX,
|
||||
"y": placeY,
|
||||
"position": Vector2D.sub(wallPosition, new Vector2D(element.indent, 0).rotate(-orientation)),
|
||||
"templateName": element.templateName,
|
||||
"angle": orientation + element.angle
|
||||
});
|
||||
@@ -336,12 +329,11 @@ function getWallAlignment(startX, startY, wall = [], style = "athen_stone", orie
|
||||
distance += indent * Math.sin(bend);
|
||||
|
||||
// Indent correction to normalize indentation
|
||||
wallX += indent * Math.cos(orientation);
|
||||
wallY += indent * Math.sin(orientation);
|
||||
wallPosition.add(new Vector2D(indent).rotate(-orientation));
|
||||
}
|
||||
|
||||
// Set the next coordinates of the next element in the wall without indentation adjustment
|
||||
wallX -= distance * Math.sin(orientation);
|
||||
wallY += distance * Math.cos(orientation);
|
||||
wallPosition.add(new Vector2D(distance, 0).rotate(-orientation).perpendicular());
|
||||
}
|
||||
}
|
||||
return alignment;
|
||||
@@ -357,13 +349,7 @@ function getWallAlignment(startX, startY, wall = [], style = "athen_stone", orie
|
||||
*/
|
||||
function getCenterToFirstElement(alignment)
|
||||
{
|
||||
let centerToFirstElement = { "x": 0, "y": 0 };
|
||||
for (let align of alignment)
|
||||
{
|
||||
centerToFirstElement.x -= align.x / alignment.length;
|
||||
centerToFirstElement.y -= align.y / alignment.length;
|
||||
}
|
||||
return centerToFirstElement;
|
||||
return alignment.reduce((result, align) => result.sub(Vector2D.div(align.position, alignment.length)), new Vector2D(0, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -412,8 +398,7 @@ function validateStyle(style, playerId = 0)
|
||||
/**
|
||||
* Places an abitrary wall beginning at the location comprised of the array of elements provided.
|
||||
*
|
||||
* @param {number} startX
|
||||
* @param {number} startY
|
||||
* @param {Vector2D} position
|
||||
* @param {array} [wall] - Array of wall element types. Example: ["start", "long", "tower", "long", "end"]
|
||||
* @param {string} [style] - Wall style string.
|
||||
* @param {number} [playerId] - Identifier of the player for whom the wall will be placed.
|
||||
@@ -422,14 +407,13 @@ function validateStyle(style, playerId = 0)
|
||||
* It will then be build towards top/positive Y (if no bending wall elements like corners are used)
|
||||
* Raising orientation means the wall is rotated counter-clockwise like placeObject
|
||||
*/
|
||||
function placeWall(startX, startY, wall = [], style, playerId = 0, orientation = 0)
|
||||
function placeWall(position, wall = [], style, playerId = 0, orientation = 0)
|
||||
{
|
||||
style = validateStyle(style, playerId);
|
||||
|
||||
let AM = getWallAlignment(startX, startY, wall, style, orientation);
|
||||
for (let iWall = 0; iWall < wall.length; ++iWall)
|
||||
if (AM[iWall].templateName)
|
||||
placeObject(AM[iWall].x, AM[iWall].y, AM[iWall].templateName, playerId, AM[iWall].angle);
|
||||
for (let align of getWallAlignment(position, wall, style, orientation))
|
||||
if (align.templateName)
|
||||
placeObject(align.position, align.templateName, playerId, align.angle);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -439,14 +423,13 @@ function placeWall(startX, startY, wall = [], style, playerId = 0, orientation =
|
||||
* The fortress wall should always start with the main entrance (like
|
||||
* "entry" or "gate") to get the orientation correct.
|
||||
*
|
||||
* @param {number} centerX
|
||||
* @param {number} centerY
|
||||
* @param {Vector2D} centerPosition
|
||||
* @param {object} [fortress] - If not provided, defaults to the predefined "medium" fortress type.
|
||||
* @param {string} [style] - Wall style string.
|
||||
* @param {number} [playerId] - Identifier of the player for whom the wall will be placed.
|
||||
* @param {number} [orientation] - Angle the first wall element (should be a gate or entrance) is placed. Default is 0
|
||||
*/
|
||||
function placeCustomFortress(centerX, centerY, fortress, style, playerId = 0, orientation = 0)
|
||||
function placeCustomFortress(centerPosition, fortress, style, playerId = 0, orientation = 0)
|
||||
{
|
||||
fortress = fortress || g_FortressTypes.medium;
|
||||
style = validateStyle(style, playerId);
|
||||
@@ -454,12 +437,16 @@ function placeCustomFortress(centerX, centerY, fortress, style, playerId = 0, or
|
||||
// Calculate center if fortress.centerToFirstElement is undefined (default)
|
||||
let centerToFirstElement = fortress.centerToFirstElement;
|
||||
if (centerToFirstElement === undefined)
|
||||
centerToFirstElement = getCenterToFirstElement(getWallAlignment(0, 0, fortress.wall, style));
|
||||
centerToFirstElement = getCenterToFirstElement(getWallAlignment(new Vector2D(0, 0), fortress.wall, style));
|
||||
|
||||
// Placing the fortress wall
|
||||
let startX = centerX + centerToFirstElement.x * Math.cos(orientation) - centerToFirstElement.y * Math.sin(orientation);
|
||||
let startY = centerY + centerToFirstElement.y * Math.cos(orientation) + centerToFirstElement.x * Math.sin(orientation);
|
||||
placeWall(startX, startY, fortress.wall, style, playerId, orientation);
|
||||
let position = Vector2D.sum([
|
||||
centerPosition,
|
||||
new Vector2D(centerToFirstElement.x, 0).rotate(-orientation),
|
||||
new Vector2D(centerToFirstElement.y, 0).perpendicular().rotate(-orientation)
|
||||
]);
|
||||
|
||||
placeWall(position, fortress.wall, style, playerId, orientation);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -469,10 +456,9 @@ function placeCustomFortress(centerX, centerY, fortress, style, playerId = 0, or
|
||||
*
|
||||
* @param {string} [type] - Predefined fortress type, as used as a key in g_FortressTypes.
|
||||
*/
|
||||
function placeFortress(centerX, centerY, type = "medium", style, playerId = 0, orientation = 0)
|
||||
function placeFortress(centerPosition, type = "medium", style, playerId = 0, orientation = 0)
|
||||
{
|
||||
// Call placeCustomFortress with the given arguments
|
||||
placeCustomFortress(centerX, centerY, g_FortressTypes[type], style, playerId, orientation);
|
||||
placeCustomFortress(centerPosition, g_FortressTypes[type], style, playerId, orientation);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -481,15 +467,13 @@ function placeFortress(centerX, centerY, type = "medium", style, playerId = 0, o
|
||||
*
|
||||
* Note: Any "bending" wall pieces passed will be complained about.
|
||||
*
|
||||
* @param {number} startX - Approximate start point of the wall.
|
||||
* @param {number} startY - Approximate start point of the wall.
|
||||
* @param {number} targetX - Approximate end point of the wall.
|
||||
* @param {number} targetY - Approximate end point of the wall.
|
||||
* @param {Vector2D} startPosition - Approximate start point of the wall.
|
||||
* @param {Vector2D} targetPosition - Approximate end point of the wall.
|
||||
* @param {array} [wallPart=["tower", "long"]]
|
||||
* @param {number} [playerId]
|
||||
* @param {boolean} [endWithFirst] - If true, the first wall element will also be the last.
|
||||
*/
|
||||
function placeLinearWall(startX, startY, targetX, targetY, wallPart = undefined, style, playerId = 0, endWithFirst = true)
|
||||
function placeLinearWall(startPosition, targetPosition, wallPart = undefined, style, playerId = 0, endWithFirst = true)
|
||||
{
|
||||
wallPart = wallPart || ["tower", "long"];
|
||||
style = validateStyle(style, playerId);
|
||||
@@ -501,7 +485,7 @@ function placeLinearWall(startX, startY, targetX, targetY, wallPart = undefined,
|
||||
|
||||
// Setup number of wall parts
|
||||
|
||||
let totalLength = Math.euclidDistance2D(startX, startY, targetX, targetY);
|
||||
let totalLength = startPosition.distanceTo(targetPosition);
|
||||
let wallPartLength = getWallLength(style, wallPart);
|
||||
let numParts = Math.ceil(totalLength / wallPartLength);
|
||||
if (endWithFirst)
|
||||
@@ -513,47 +497,39 @@ function placeLinearWall(startX, startY, targetX, targetY, wallPart = undefined,
|
||||
scaleFactor = totalLength / (numParts * wallPartLength + getWallElement(wallPart[0], style).length);
|
||||
|
||||
// Setup angle
|
||||
let wallAngle = getAngle(startX, startY, targetX, targetY); // NOTE: function "getAngle()" is about to be changed...
|
||||
let wallAngle = getAngle(startPosition.x, startPosition.y, targetPosition.x, targetPosition.y);
|
||||
let placeAngle = wallAngle - Math.PI / 2;
|
||||
|
||||
// Place wall entities
|
||||
let x = startX;
|
||||
let y = startY;
|
||||
let position = startPosition.clone();
|
||||
let overlap = g_WallStyles[style].overlap;
|
||||
for (let partIndex = 0; partIndex < numParts; ++partIndex)
|
||||
{
|
||||
for (let elementIndex = 0; elementIndex < wallPart.length; ++elementIndex)
|
||||
{
|
||||
let wallEle = getWallElement(wallPart[elementIndex], style);
|
||||
|
||||
let wallLength = (wallEle.length - overlap) / 2;
|
||||
let distX = scaleFactor * wallLength * Math.cos(wallAngle);
|
||||
let distY = scaleFactor * wallLength * Math.sin(wallAngle);
|
||||
let dist = new Vector2D(scaleFactor * wallLength, 0).rotate(-wallAngle);
|
||||
|
||||
// Length correction
|
||||
x += distX;
|
||||
y += distY;
|
||||
position.add(dist);
|
||||
|
||||
// Indent correction
|
||||
let placeX = x - wallEle.indent * Math.sin(wallAngle);
|
||||
let placeY = y + wallEle.indent * Math.cos(wallAngle);
|
||||
let place = Vector2D.add(position, new Vector2D(0, wallEle.indent).rotate(-wallAngle));
|
||||
|
||||
// Placement
|
||||
if (wallEle.templateName)
|
||||
placeObject(placeX, placeY, wallEle.templateName, playerId, placeAngle + wallEle.angle);
|
||||
placeObject(place, wallEle.templateName, playerId, placeAngle + wallEle.angle);
|
||||
|
||||
// Prep for next object
|
||||
x += distX;
|
||||
y += distY;
|
||||
position.add(dist);
|
||||
}
|
||||
}
|
||||
|
||||
if (endWithFirst)
|
||||
{
|
||||
let wallEle = getWallElement(wallPart[0], style);
|
||||
let wallLength = (wallEle.length - overlap) / 2;
|
||||
x += scaleFactor * wallLength * Math.cos(wallAngle);
|
||||
y += scaleFactor * wallLength * Math.sin(wallAngle);
|
||||
position.add(new Vector2D(scaleFactor * wallLength, 0).rotate(-wallAngle));
|
||||
if (wallEle.templateName)
|
||||
placeObject(x, y, wallEle.templateName, playerId, placeAngle + wallEle.angle);
|
||||
placeObject(position, wallEle.templateName, playerId, placeAngle + wallEle.angle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -568,8 +544,7 @@ function placeLinearWall(startX, startY, targetX, targetY, wallPart = undefined,
|
||||
*
|
||||
* Note: Any "bending" wall pieces passed will be complained about.
|
||||
*
|
||||
* @param {number} centerX - Center of the circle or arc.
|
||||
* @param {number} centerY - Center of the circle or arc.
|
||||
* @param {Vector2D} center - Center of the circle or arc.
|
||||
* @param (number} radius - Approximate radius of the circle. (Given the maxBendOff argument)
|
||||
* @param {array} [wallPart]
|
||||
* @param {string} [style]
|
||||
@@ -579,7 +554,7 @@ function placeLinearWall(startX, startY, targetX, targetY, wallPart = undefined,
|
||||
* @param {boolean} [endWithFirst] - If true, the first wall element will also be the last. For full circles, the default is false. For arcs, true.
|
||||
* @param {number} [maxBendOff] Optional. How irregular the circle should be. 0 means regular circle, PI/2 means very irregular. Default is 0 (regular circle)
|
||||
*/
|
||||
function placeCircularWall(centerX, centerY, radius, wallPart, style, playerId = 0, orientation = 0, maxAngle = Math.PI * 2, endWithFirst, maxBendOff = 0)
|
||||
function placeCircularWall(center, radius, wallPart, style, playerId = 0, orientation = 0, maxAngle = Math.PI * 2, endWithFirst, maxBendOff = 0)
|
||||
{
|
||||
wallPart = wallPart || ["tower", "long"];
|
||||
style = validateStyle(style, playerId);
|
||||
@@ -609,8 +584,7 @@ function placeCircularWall(centerX, centerY, radius, wallPart, style, playerId =
|
||||
|
||||
// Place wall entities
|
||||
let actualAngle = orientation + (Math.PI * 2 - maxAngle) / 2;
|
||||
let x = centerX + radius * Math.cos(actualAngle);
|
||||
let y = centerY + radius * Math.sin(actualAngle);
|
||||
let position = Vector2D.add(center, new Vector2D(radius, 0).rotate(-actualAngle));
|
||||
let overlap = g_WallStyles[style].overlap;
|
||||
for (let partIndex = 0; partIndex < numParts; ++partIndex)
|
||||
for (let wallEle of wallPart)
|
||||
@@ -619,36 +593,30 @@ function placeCircularWall(centerX, centerY, radius, wallPart, style, playerId =
|
||||
|
||||
// Width correction
|
||||
let addAngle = scaleFactor * (wallEle.length - overlap) / radius;
|
||||
let targetX = centerX + radius * Math.cos(actualAngle + addAngle);
|
||||
let targetY = centerY + radius * Math.sin(actualAngle + addAngle);
|
||||
let placeX = x + (targetX - x) / 2;
|
||||
let placeY = y + (targetY - y) / 2;
|
||||
let target = Vector2D.add(center, new Vector2D(radius, 0).rotate(-actualAngle - addAngle));
|
||||
let place = Vector2D.average([position, target]);
|
||||
let placeAngle = actualAngle + addAngle / 2;
|
||||
|
||||
// Indent correction
|
||||
placeX -= wallEle.indent * Math.cos(placeAngle);
|
||||
placeY -= wallEle.indent * Math.sin(placeAngle);
|
||||
place.sub(new Vector2D(wallEle.indent, 0).rotate(-placeAngle));
|
||||
|
||||
// Placement
|
||||
if (wallEle.templateName)
|
||||
placeObject(placeX, placeY, wallEle.templateName, playerId, placeAngle + wallEle.angle);
|
||||
placeObject(place, wallEle.templateName, playerId, placeAngle + wallEle.angle);
|
||||
|
||||
// Prepare for the next wall element
|
||||
actualAngle += addAngle;
|
||||
x = centerX + radius * Math.cos(actualAngle);
|
||||
y = centerY + radius * Math.sin(actualAngle);
|
||||
position = Vector2D.add(center, new Vector2D(radius, 0).rotate(-actualAngle));
|
||||
}
|
||||
|
||||
if (endWithFirst)
|
||||
{
|
||||
let wallEle = getWallElement(wallPart[0], style);
|
||||
let addAngle = scaleFactor * wallEle.length / radius;
|
||||
let targetX = centerX + radius * Math.cos(actualAngle + addAngle);
|
||||
let targetY = centerY + radius * Math.sin(actualAngle + addAngle);
|
||||
let placeX = x + (targetX - x) / 2;
|
||||
let placeY = y + (targetY - y) / 2;
|
||||
let target = Vector2D.add(center, new Vector2D(radius, 0).rotate(-actualAngle - addAngle))
|
||||
let place = Vector2D.average([position, target]);
|
||||
let placeAngle = actualAngle + addAngle / 2;
|
||||
placeObject(placeX, placeY, wallEle.templateName, playerId, placeAngle + wallEle.angle);
|
||||
placeObject(place, wallEle.templateName, playerId, placeAngle + wallEle.angle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -658,8 +626,7 @@ function placeCircularWall(centerX, centerY, radius, wallPart, style, playerId =
|
||||
*
|
||||
* Note: Any "bending" wall pieces passed will be ignored.
|
||||
*
|
||||
* @param {number} centerX
|
||||
* @param {number} centerY
|
||||
* @param {Vector2D} centerPosition
|
||||
* @param {number} radius
|
||||
* @param {array} [wallPart]
|
||||
* @param {string} [cornerWallElement] - Wall element to be placed at the polygon's corners.
|
||||
@@ -669,42 +636,35 @@ function placeCircularWall(centerX, centerY, radius, wallPart, style, playerId =
|
||||
* @param {number} [numCorners] - How many corners the polygon will have.
|
||||
* @param {boolean} [skipFirstWall] - If the first linear wall part will be left opened as entrance.
|
||||
*/
|
||||
function placePolygonalWall(centerX, centerY, radius, wallPart, cornerWallElement = "tower", style, playerId = 0, orientation = 0, numCorners = 8, skipFirstWall = true)
|
||||
function placePolygonalWall(centerPosition, radius, wallPart, cornerWallElement = "tower", style, playerId = 0, orientation = 0, numCorners = 8, skipFirstWall = true)
|
||||
{
|
||||
wallPart = wallPart || ["long", "tower"];
|
||||
style = validateStyle(style, playerId);
|
||||
|
||||
// Setup angles
|
||||
let angleAdd = Math.PI * 2 / numCorners;
|
||||
let angleStart = orientation - angleAdd / 2;
|
||||
let corners = new Array(numCorners).fill(0).map((zero, i) =>
|
||||
Vector2D.add(centerPosition, new Vector2D(radius, 0).rotate(-angleStart - i * angleAdd)));
|
||||
|
||||
// Setup corners
|
||||
let corners = [];
|
||||
for (let i = 0; i < numCorners; ++i)
|
||||
corners.push([
|
||||
centerX + radius * Math.cos(angleStart + i * angleAdd),
|
||||
centerY + radius * Math.sin(angleStart + i * angleAdd)
|
||||
]);
|
||||
|
||||
// Place Corners and walls
|
||||
for (let i = 0; i < numCorners; ++i)
|
||||
{
|
||||
let angleToCorner = getAngle(corners[i][0], corners[i][1], centerX, centerY);
|
||||
placeObject(corners[i][0], corners[i][1], getWallElement(cornerWallElement, style).templateName, playerId, angleToCorner);
|
||||
let angleToCorner = getAngle(corners[i].x, corners[i].y, centerPosition.x, centerPosition.y);
|
||||
placeObject(corners[i], getWallElement(cornerWallElement, style).templateName, playerId, angleToCorner);
|
||||
|
||||
if (!skipFirstWall || i != 0)
|
||||
{
|
||||
let cornerLength = getWallElement(cornerWallElement, style).length / 2;
|
||||
let cornerAngle = angleToCorner + angleAdd / 2;
|
||||
let cornerX = cornerLength * Math.sin(cornerAngle);
|
||||
let cornerY = cornerLength * Math.cos(cornerAngle);
|
||||
let targetCorner = (i + 1) % numCorners;
|
||||
let cornerPosition = new Vector2D(cornerLength, 0).rotate(-cornerAngle).perpendicular();
|
||||
|
||||
placeLinearWall(
|
||||
// Adjustment to the corner element width (approximately)
|
||||
corners[i][0] + cornerX, // startX
|
||||
corners[i][1] - cornerY, // startY
|
||||
corners[targetCorner][0] - cornerX, // targetX
|
||||
corners[targetCorner][1] + cornerY, // targetY
|
||||
wallPart, style, playerId);
|
||||
Vector2D.sub(corners[i], cornerPosition),
|
||||
Vector2D.add(corners[targetCorner], cornerPosition),
|
||||
wallPart,
|
||||
style,
|
||||
playerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -718,8 +678,7 @@ function placePolygonalWall(centerX, centerY, radius, wallPart, cornerWallElemen
|
||||
*
|
||||
* Note: The wallPartsAssortment is last because it's the hardest to set.
|
||||
*
|
||||
* @param {number} centerX
|
||||
* @param {number} centerY
|
||||
* @param {Vector2D} centerPosition
|
||||
* @param {number} radius
|
||||
* @param {string} [cornerWallElement] - Wall element to be placed at the polygon's corners.
|
||||
* @param {string} [style]
|
||||
@@ -730,7 +689,7 @@ function placePolygonalWall(centerX, centerY, radius, wallPart, cornerWallElemen
|
||||
* @param {boolean} [skipFirstWall] - If true, the first linear wall part will be left open as an entrance.
|
||||
* @param {array} [wallPartsAssortment] - An array of wall part arrays to choose from for each linear wall connecting the corners.
|
||||
*/
|
||||
function placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement = "tower", style, playerId = 0, orientation = 0, numCorners, irregularity = 0.5, skipFirstWall = false, wallPartsAssortment)
|
||||
function placeIrregularPolygonalWall(centerPosition, radius, cornerWallElement = "tower", style, playerId = 0, orientation = 0, numCorners, irregularity = 0.5, skipFirstWall = false, wallPartsAssortment)
|
||||
{
|
||||
style = validateStyle(style, playerId);
|
||||
numCorners = numCorners || randIntInclusive(5, 7);
|
||||
@@ -775,10 +734,8 @@ function placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement
|
||||
let angleActual = orientation - angleAddList[0] / 2;
|
||||
for (let i = 0; i < numCorners; ++i)
|
||||
{
|
||||
corners.push([
|
||||
centerX + radius * Math.cos(angleActual),
|
||||
centerY + radius * Math.sin(angleActual)
|
||||
]);
|
||||
corners.push(Vector2D.add(centerPosition, new Vector2D(radius, 0).rotate(-angleActual)));
|
||||
|
||||
if (i < numCorners - 1)
|
||||
angleActual += angleAddList[i + 1];
|
||||
}
|
||||
@@ -801,7 +758,7 @@ function placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement
|
||||
let bestWallLength = Infinity;
|
||||
let targetCorner = (i + 1) % numCorners;
|
||||
// NOTE: This is not quite the length the wall will be in the end. Has to be tweaked...
|
||||
let wallLength = Math.euclidDistance2D(corners[i][0], corners[i][1], corners[targetCorner][0], corners[targetCorner][1]);
|
||||
let wallLength = corners[i].distanceTo(corners[targetCorner]);
|
||||
let numWallParts = Math.ceil(wallLength / maxWallPartLength);
|
||||
for (let partIndex = 0; partIndex < wallPartsAssortment.length; ++partIndex)
|
||||
{
|
||||
@@ -818,21 +775,24 @@ function placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement
|
||||
// Place Corners and walls
|
||||
for (let i = 0; i < numCorners; ++i)
|
||||
{
|
||||
let angleToCorner = getAngle(corners[i][0], corners[i][1], centerX, centerY);
|
||||
placeObject(corners[i][0], corners[i][1], getWallElement(cornerWallElement, style).templateName, playerId, angleToCorner);
|
||||
let angleToCorner = getAngle(corners[i].x, corners[i].y, centerPosition.x, centerPosition.y);
|
||||
placeObject(corners[i], getWallElement(cornerWallElement, style).templateName, playerId, angleToCorner);
|
||||
if (!skipFirstWall || i != 0)
|
||||
{
|
||||
let cornerLength = getWallElement(cornerWallElement, style).length / 2;
|
||||
let targetCorner = (i + 1) % numCorners;
|
||||
let startAngle = angleToCorner + angleAddList[i] / 2;
|
||||
let targetAngle = angleToCorner + angleAddList[targetCorner] / 2;
|
||||
|
||||
|
||||
placeLinearWall(
|
||||
// Adjustment to the corner element width (approximately)
|
||||
corners[i][0] + cornerLength * Math.sin(startAngle), // startX
|
||||
corners[i][1] - cornerLength * Math.cos(startAngle), // startY
|
||||
corners[targetCorner][0] - cornerLength * Math.sin(targetAngle), // targetX
|
||||
corners[targetCorner][1] + cornerLength * Math.cos(targetAngle), // targetY
|
||||
wallPartList[i], style, playerId, false);
|
||||
Vector2D.sub(corners[i], new Vector2D(cornerLength, 0).perpendicular().rotate(-startAngle)),
|
||||
Vector2D.add(corners[targetCorner], new Vector2D(cornerLength, 0).rotate(-targetAngle - Math.PI / 2)),
|
||||
wallPartList[i],
|
||||
style,
|
||||
playerId,
|
||||
false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -848,23 +808,21 @@ function placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement
|
||||
*
|
||||
* This is the default Iberian civ bonus starting wall.
|
||||
*
|
||||
* @param {number} centerX - The approximate center coordinates of the fortress
|
||||
* @param {number} centerY - The approximate center coordinates of the fortress
|
||||
* @param {Vector2D} center - The approximate center coordinates of the fortress
|
||||
* @param {number} [radius] - The approximate radius of the wall to be placed.
|
||||
* @param {number} [playerId]
|
||||
* @param {string} [style]
|
||||
* @param {number} [irregularity] - 0 = circle, 1 = very spiky
|
||||
* @param {number} [gateOccurence] - Integer number, every n-th walls will be a gate instead.
|
||||
* @param {number} [maxTrys] - How often the function tries to find a better fitting shape.
|
||||
* @param {number} [maxTries] - How often the function tries to find a better fitting shape.
|
||||
*/
|
||||
function placeGenericFortress(centerX, centerY, radius = 20, playerId = 0, style, irregularity = 0.5, gateOccurence = 3, maxTrys = 100)
|
||||
function placeGenericFortress(center, radius = 20, playerId = 0, style, irregularity = 0.5, gateOccurence = 3, maxTries = 100)
|
||||
{
|
||||
style = validateStyle(style, playerId);
|
||||
|
||||
// Setup some vars
|
||||
let startAngle = randFloat(0, Math.PI * 2);
|
||||
let actualOffX = radius * Math.cos(startAngle);
|
||||
let actualOffY = radius * Math.sin(startAngle);
|
||||
let startAngle = randomAngle();
|
||||
let actualOff = new Vector2D(radius, 0).rotate(-startAngle);
|
||||
let actualAngle = startAngle;
|
||||
let pointDistance = getWallLength(style, ["long", "tower"]);
|
||||
|
||||
@@ -873,33 +831,31 @@ function placeGenericFortress(centerX, centerY, radius = 20, playerId = 0, style
|
||||
let bestPointDerivation;
|
||||
let minOverlap = 1000;
|
||||
let overlap;
|
||||
while (tries < maxTrys && minOverlap > g_WallStyles[style].overlap)
|
||||
while (tries < maxTries && minOverlap > g_WallStyles[style].overlap)
|
||||
{
|
||||
let pointDerivation = [];
|
||||
let distanceToTarget = 1000;
|
||||
let targetReached = false;
|
||||
while (!targetReached)
|
||||
while (true)
|
||||
{
|
||||
let indent = randFloat(-irregularity * pointDistance, irregularity * pointDistance);
|
||||
let tmpAngle = getAngle(actualOffX, actualOffY,
|
||||
(radius + indent) * Math.cos(actualAngle + pointDistance / radius),
|
||||
(radius + indent) * Math.sin(actualAngle + pointDistance / radius)
|
||||
);
|
||||
actualOffX += pointDistance * Math.cos(tmpAngle);
|
||||
actualOffY += pointDistance * Math.sin(tmpAngle);
|
||||
actualAngle = getAngle(0, 0, actualOffX, actualOffY);
|
||||
pointDerivation.push([actualOffX, actualOffY]);
|
||||
distanceToTarget = Math.euclidDistance2D(actualOffX, actualOffY, ...pointDerivation[0]);
|
||||
let tmp = new Vector2D(radius + indent, 0).rotate(-actualAngle - pointDistance / radius);
|
||||
let tmpAngle = getAngle(actualOff.x, actualOff.y, tmp.x, tmp.y);
|
||||
|
||||
actualOff.add(new Vector2D(pointDistance, 0).rotate(-tmpAngle));
|
||||
actualAngle = getAngle(0, 0, actualOff.x, actualOff.y);
|
||||
pointDerivation.push(actualOff.clone());
|
||||
distanceToTarget = pointDerivation[0].distanceTo(actualOff);
|
||||
|
||||
let numPoints = pointDerivation.length;
|
||||
if (numPoints > 3 && distanceToTarget < pointDistance) // Could be done better...
|
||||
{
|
||||
targetReached = true;
|
||||
overlap = pointDistance - Math.euclidDistance2D(...pointDerivation[numPoints - 1], ...pointDerivation[0]);
|
||||
overlap = pointDistance - pointDerivation[numPoints - 1].distanceTo(pointDerivation[0]);
|
||||
if (overlap < minOverlap)
|
||||
{
|
||||
minOverlap = overlap;
|
||||
bestPointDerivation = pointDerivation;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
++tries;
|
||||
@@ -909,34 +865,24 @@ function placeGenericFortress(centerX, centerY, radius = 20, playerId = 0, style
|
||||
// Place wall
|
||||
for (let pointIndex = 0; pointIndex < bestPointDerivation.length; ++pointIndex)
|
||||
{
|
||||
let startX = centerX + bestPointDerivation[pointIndex][0];
|
||||
let startY = centerY + bestPointDerivation[pointIndex][1];
|
||||
let targetX = centerX + bestPointDerivation[(pointIndex + 1) % bestPointDerivation.length][0];
|
||||
let targetY = centerY + bestPointDerivation[(pointIndex + 1) % bestPointDerivation.length][1];
|
||||
let angle = getAngle(startX, startY, targetX, targetY);
|
||||
let start = Vector2D.add(center, bestPointDerivation[pointIndex]);
|
||||
let target = Vector2D.add(center, bestPointDerivation[(pointIndex + 1) % bestPointDerivation.length]);
|
||||
let angle = getAngle(start.x, start.y, target.x, target.y);
|
||||
|
||||
let element = (pointIndex + 1) % gateOccurence == 0 ? "gate" : "long";
|
||||
element = getWallElement(element, style);
|
||||
|
||||
if (element.templateName)
|
||||
{
|
||||
let dist = Math.euclidDistance2D(startX, startY, targetX, targetY) / 2;
|
||||
placeObject(
|
||||
startX + dist * Math.cos(angle), // placeX
|
||||
startY + dist * Math.sin(angle), // placeY
|
||||
element.templateName, playerId, angle - Math.PI / 2 + element.angle
|
||||
);
|
||||
let pos = Vector2D.add(start, new Vector2D(start.distanceTo(target) / 2, 0).rotate(-angle));
|
||||
placeObject(pos, element.templateName, playerId, angle - Math.PI / 2 + element.angle);
|
||||
}
|
||||
|
||||
// Place tower
|
||||
startX = centerX + bestPointDerivation[(pointIndex + bestPointDerivation.length - 1) % bestPointDerivation.length][0];
|
||||
startY = centerY + bestPointDerivation[(pointIndex + bestPointDerivation.length - 1) % bestPointDerivation.length][1];
|
||||
angle = getAngle(startX, startY, targetX, targetY);
|
||||
start = Vector2D.add(center, bestPointDerivation[(pointIndex + bestPointDerivation.length - 1) % bestPointDerivation.length]);
|
||||
angle = getAngle(start.x, start.y, target.x, target.y);
|
||||
|
||||
let tower = getWallElement("tower", style);
|
||||
placeObject(
|
||||
centerX + bestPointDerivation[pointIndex][0],
|
||||
centerY + bestPointDerivation[pointIndex][1],
|
||||
tower.templateName, playerId, angle - Math.PI / 2 + tower.angle
|
||||
);
|
||||
placeObject(Vector2D.add(center, bestPointDerivation[pointIndex]), tower.templateName, playerId, angle - Math.PI / 2 + tower.angle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,11 +94,11 @@ for (let i = 0; i < numPlayers; ++i)
|
||||
log("Placing treasure seeker woman...");
|
||||
let femaleLocation = findLocationInDirectionBasedOnHeight(playerPosition[i], mapCenter, -3 , 3.5, 3).round();
|
||||
addToClass(femaleLocation.x, femaleLocation.y, clWomen);
|
||||
placeObject(femaleLocation.x, femaleLocation.y, oTreasureSeeker, playerIDs[i], playerAngle[i] + Math.PI);
|
||||
placeObject(femaleLocation, oTreasureSeeker, playerIDs[i], playerAngle[i] + Math.PI);
|
||||
|
||||
log("Placing attacker spawn point....");
|
||||
placeObject(attacker[i].x, attacker[i].y, aWaypointFlag, 0, Math.PI / 2);
|
||||
placeObject(attacker[i].x, attacker[i].y, triggerPointAttacker, playerIDs[i], Math.PI / 2);
|
||||
placeObject(attacker[i], aWaypointFlag, 0, Math.PI / 2);
|
||||
placeObject(attacker[i], triggerPointAttacker, playerIDs[i], Math.PI / 2);
|
||||
|
||||
log("Preventing mountains in the area between player and attackers...");
|
||||
addCivicCenterAreaToClass(playerPosition[i], clPlayer);
|
||||
|
||||
@@ -155,7 +155,7 @@ paintRiver({
|
||||
if (plantID % plantFrequency == 0)
|
||||
{
|
||||
plantID = 0;
|
||||
placeObject(position.x, position.y, aPlants, 0, randomAngle());
|
||||
placeObject(position, aPlants, 0, randomAngle());
|
||||
}
|
||||
++plantID;
|
||||
},
|
||||
|
||||
@@ -50,8 +50,8 @@ var mapSize = g_Map.getSize();
|
||||
const distToMapBorder = 5;
|
||||
const distToOtherWalls = 10;
|
||||
var buildableMapSize = mapSize - 2 * distToMapBorder;
|
||||
var actualX = distToMapBorder;
|
||||
var actualY = distToMapBorder;
|
||||
|
||||
var position = new Vector2D(distToMapBorder, distToMapBorder);
|
||||
var playerID = 0;
|
||||
const wallStyleList = Object.keys(g_WallStyles);
|
||||
|
||||
@@ -69,18 +69,14 @@ const wallStyleList = Object.keys(g_WallStyles);
|
||||
*/
|
||||
for (let styleIndex in wallStyleList)
|
||||
{
|
||||
let x = actualX + styleIndex * buildableMapSize / wallStyleList.length;
|
||||
let y = actualY;
|
||||
let pos = Vector2D.add(position, new Vector2D(styleIndex * buildableMapSize / wallStyleList.length));
|
||||
let wall = ['start', 'long', 'tower', 'tower', 'tower', 'medium', 'outpost', 'medium', 'cornerOut', 'medium', 'cornerIn', 'medium', 'house', 'end', 'entryTower', 'start', 'short', 'barracks', 'gate', 'tower', 'medium', 'fort', 'medium', 'end'];
|
||||
let style = wallStyleList[styleIndex];
|
||||
let orientation = Math.PI / 16 * Math.sin(styleIndex * Math.PI / 4);
|
||||
|
||||
placeWall(x, y, wall, style, playerID, orientation);
|
||||
placeWall(pos, wall, style, playerID, orientation);
|
||||
}
|
||||
|
||||
// Prep for next set of walls
|
||||
actualX = distToMapBorder;
|
||||
actualY += 80 + distToOtherWalls;
|
||||
position.y += 80 + distToOtherWalls;
|
||||
|
||||
/**
|
||||
* Default fortress placement (chosen by fortress type string)
|
||||
@@ -100,19 +96,21 @@ var fortressRadius = 15; // The space the fortresses take in average. Just for d
|
||||
|
||||
for (let styleIndex in wallStyleList)
|
||||
{
|
||||
let x = actualX + fortressRadius + styleIndex * buildableMapSize / wallStyleList.length;
|
||||
let y = actualY + fortressRadius;
|
||||
let type = "tiny";
|
||||
let style = wallStyleList[styleIndex];
|
||||
let orientation = styleIndex * Math.PI / 32;
|
||||
|
||||
placeObject(x, y, "other/obelisk", playerID, orientation);
|
||||
placeFortress(x, y, type, style, playerID, orientation);
|
||||
let pos = Vector2D.sum([
|
||||
position,
|
||||
new Vector2D(1, 1).mult(fortressRadius),
|
||||
new Vector2D(styleIndex * buildableMapSize / wallStyleList.length, 0)
|
||||
]);
|
||||
|
||||
placeObject(pos, "other/obelisk", playerID, orientation);
|
||||
placeFortress(pos, type, style, playerID, orientation);
|
||||
}
|
||||
|
||||
// Prep for next set of walls
|
||||
actualX = distToMapBorder;
|
||||
actualY += 2 * fortressRadius + distToOtherWalls;
|
||||
position.y += 2 * fortressRadius + distToOtherWalls;
|
||||
|
||||
/**
|
||||
* 'Generic' fortress placement (iberian wall circuit code)
|
||||
@@ -125,20 +123,22 @@ actualY += 2 * fortressRadius + distToOtherWalls;
|
||||
*
|
||||
* We also supply a radius value to dictate how wide the circuit of walls should be.
|
||||
*/
|
||||
var radius = Math.min((mapSize - actualY - distToOtherWalls) / 3, (buildableMapSize / wallStyleList.length - distToOtherWalls) / 2);
|
||||
var radius = Math.min((mapSize - position.y - distToOtherWalls) / 3, (buildableMapSize / wallStyleList.length - distToOtherWalls) / 2);
|
||||
for (let styleIndex in wallStyleList)
|
||||
{
|
||||
let centerX = actualX + radius + styleIndex * buildableMapSize / wallStyleList.length;
|
||||
let centerY = actualY + radius;
|
||||
let style = wallStyleList[styleIndex];
|
||||
|
||||
placeObject(centerX, centerY, 'other/obelisk', playerID, 0);
|
||||
placeGenericFortress(centerX, centerY, radius, playerID, style);
|
||||
let pos = Vector2D.sum([
|
||||
position,
|
||||
new Vector2D(radius, radius),
|
||||
new Vector2D(styleIndex * buildableMapSize / wallStyleList.length, 0)
|
||||
]);
|
||||
|
||||
placeObject(pos, "other/obelisk", playerID, 0);
|
||||
placeGenericFortress(pos, radius, playerID, style);
|
||||
}
|
||||
|
||||
// Prep for next set of walls
|
||||
actualX = distToMapBorder;
|
||||
actualY += 2 * radius + distToOtherWalls;
|
||||
position.y += 2 * radius + distToOtherWalls;
|
||||
|
||||
/**
|
||||
* Circular wall placement
|
||||
@@ -162,11 +162,10 @@ actualY += 2 * radius + distToOtherWalls;
|
||||
* arc faces. If the wall is to be a complete circle, then this is used as
|
||||
* the orientation of the first wall piece.
|
||||
*/
|
||||
radius = Math.min((mapSize - actualY - distToOtherWalls) / 3, (buildableMapSize / wallStyleList.length - distToOtherWalls) / 2);
|
||||
radius = Math.min((mapSize - position.y - distToOtherWalls) / 3, (buildableMapSize / wallStyleList.length - distToOtherWalls) / 2);
|
||||
for (let styleIndex in wallStyleList)
|
||||
{
|
||||
let centerX = actualX + radius + styleIndex * buildableMapSize / wallStyleList.length;
|
||||
let centerY = actualY + radius;
|
||||
let center = Vector2D.sum([position, new Vector2D(1, 1).mult(radius), new Vector2D(styleIndex * buildableMapSize / wallStyleList.length, 0)]);
|
||||
let wallPart = ['tower', 'medium', 'house'];
|
||||
let style = wallStyleList[styleIndex];
|
||||
let orientation = styleIndex * Math.PI / 16;
|
||||
@@ -176,13 +175,11 @@ for (let styleIndex in wallStyleList)
|
||||
// If less than Pi * 2, then the wall will be an arc.
|
||||
let maxAngle = Math.PI / 2 * (styleIndex % 3 + 2);
|
||||
|
||||
placeObject(centerX, centerY, 'other/obelisk', playerID, orientation);
|
||||
placeCircularWall(centerX, centerY, radius, wallPart, style, playerID, orientation, maxAngle);
|
||||
placeObject(center, "other/obelisk", playerID, orientation);
|
||||
placeCircularWall(center, radius, wallPart, style, playerID, orientation, maxAngle);
|
||||
}
|
||||
|
||||
// Prep for next set of walls.
|
||||
actualX = distToMapBorder;
|
||||
actualY += 2 * radius + distToOtherWalls;
|
||||
position.y += 2 * radius + distToOtherWalls;
|
||||
|
||||
/**
|
||||
* Regular Polygonal wall placement
|
||||
@@ -208,11 +205,11 @@ actualY += 2 * radius + distToOtherWalls;
|
||||
* outward side facing or, if the `skipFirstWall` argument is true, the
|
||||
* opening in the wall.
|
||||
*/
|
||||
radius = Math.min((mapSize - actualY - distToOtherWalls) / 2, (buildableMapSize / wallStyleList.length - distToOtherWalls) / 2);
|
||||
|
||||
radius = Math.min((mapSize - position.y - distToOtherWalls) / 2, (buildableMapSize / wallStyleList.length - distToOtherWalls) / 2);
|
||||
for (let styleIndex in wallStyleList)
|
||||
{
|
||||
let centerX = actualX + radius + styleIndex * buildableMapSize / wallStyleList.length;
|
||||
let centerY = actualY + radius;
|
||||
let centerPosition = Vector2D.sum([position, new Vector2D(1, 1).mult(radius), new Vector2D(styleIndex * buildableMapSize / wallStyleList.length, 0)]);
|
||||
let wallParts = ['medium', 'tower']; // Function default: ['long', 'tower']
|
||||
|
||||
// Which wall element to use for the corners of the polygon
|
||||
@@ -227,13 +224,11 @@ for (let styleIndex in wallStyleList)
|
||||
// If true, the first side will not be drawn, leaving the wall open.
|
||||
let skipFirstWall = true;
|
||||
|
||||
placeObject(centerX, centerY, 'other/obelisk', playerID, orientation);
|
||||
placePolygonalWall(centerX, centerY, radius, wallParts, cornerWallElement, style, playerID, orientation, numCorners, skipFirstWall);
|
||||
placeObject(centerPosition, "other/obelisk", playerID, orientation);
|
||||
placePolygonalWall(centerPosition, radius, wallParts, cornerWallElement, style, playerID, orientation, numCorners, skipFirstWall);
|
||||
}
|
||||
|
||||
// Prep for next set of walls.
|
||||
actualX = distToMapBorder;
|
||||
actualY += 2 * radius + distToOtherWalls;
|
||||
position.y += 2 * radius + distToOtherWalls;
|
||||
|
||||
/**
|
||||
* Irregular Polygonal wall placement
|
||||
@@ -263,11 +258,14 @@ actualY += 2 * radius + distToOtherWalls;
|
||||
* the wall. It is not defined in this example (so as to use the defaults)
|
||||
* as it is not easy to comprehend.
|
||||
*/
|
||||
radius = Math.min((mapSize - actualY - distToOtherWalls) / 2, (buildableMapSize / wallStyleList.length - distToOtherWalls) / 2); // The radius of wall polygons
|
||||
radius = Math.min((mapSize - position.y - distToOtherWalls) / 2, (buildableMapSize / wallStyleList.length - distToOtherWalls) / 2); // The radius of wall polygons
|
||||
for (let styleIndex in wallStyleList)
|
||||
{
|
||||
let centerX = actualX + radius + styleIndex * buildableMapSize / wallStyleList.length;
|
||||
let centerY = actualY + radius;
|
||||
let centerPosition = Vector2D.sum([
|
||||
position,
|
||||
new Vector2D(1, 1).mult(radius),
|
||||
new Vector2D(styleIndex * buildableMapSize / wallStyleList.length, 0)
|
||||
]);
|
||||
|
||||
// Which wall element type will be used for the corners of the polygon.
|
||||
let cornerWallElement = 'tower';
|
||||
@@ -284,13 +282,11 @@ for (let styleIndex in wallStyleList)
|
||||
// If true, the first side will not be drawn, leaving the wall open.
|
||||
let skipFirstWall = true;
|
||||
|
||||
placeObject(centerX, centerY, 'other/obelisk', playerID, orientation);
|
||||
placeIrregularPolygonalWall(centerX, centerY, radius, cornerWallElement, style, playerID, orientation, numCorners, irregularity, skipFirstWall);
|
||||
placeObject(centerPosition, "other/obelisk", playerID, orientation);
|
||||
placeIrregularPolygonalWall(centerPosition, radius, cornerWallElement, style, playerID, orientation, numCorners, irregularity, skipFirstWall);
|
||||
}
|
||||
|
||||
// Prep for next set of walls.
|
||||
actualX = distToMapBorder;
|
||||
actualY += 2 * radius + distToOtherWalls;
|
||||
position.y += 2 * radius + distToOtherWalls;
|
||||
|
||||
/**
|
||||
* Linear wall placement
|
||||
@@ -306,25 +302,20 @@ actualY += 2 * radius + distToOtherWalls;
|
||||
* of the walls is facing the top of the screen.
|
||||
*/
|
||||
// Two vars, just for this map; firstly how long the longest wall will be.
|
||||
var maxWallLength = (mapSize - actualY - distToMapBorder - distToOtherWalls);
|
||||
var maxWallLength = (mapSize - position.y - distToMapBorder - distToOtherWalls);
|
||||
// And secondly, how many walls of the same style will be placed.
|
||||
var numWallsPerStyle = Math.floor(buildableMapSize / distToOtherWalls / wallStyleList.length);
|
||||
|
||||
for (let styleIndex in wallStyleList)
|
||||
for (let wallIndex = 0; wallIndex < numWallsPerStyle; ++wallIndex)
|
||||
{
|
||||
// Start point.
|
||||
let startX = actualX + (styleIndex * numWallsPerStyle + wallIndex) * buildableMapSize / wallStyleList.length / numWallsPerStyle;
|
||||
let startY = actualY;
|
||||
let offsetX = (styleIndex * numWallsPerStyle + wallIndex) * buildableMapSize / wallStyleList.length / numWallsPerStyle;
|
||||
let start = Vector2D.add(position, new Vector2D(offsetX, 0));
|
||||
|
||||
// End point.
|
||||
let endX = startX;
|
||||
let endY = actualY + (wallIndex + 1) * maxWallLength / numWallsPerStyle;
|
||||
let offsetY = (wallIndex + 1) * maxWallLength / numWallsPerStyle;
|
||||
let end = Vector2D.add(position, new Vector2D(offsetX, offsetY));
|
||||
|
||||
let wallPart = ['tower', 'medium'];
|
||||
let style = wallStyleList[styleIndex];
|
||||
|
||||
placeLinearWall(startX, startY, endX, endY, wallPart, style, playerID);
|
||||
placeLinearWall(start, end, ['tower', 'medium'], wallStyleList[styleIndex], playerID);
|
||||
}
|
||||
|
||||
g_Map.ExportMap();
|
||||
|
||||
@@ -203,8 +203,7 @@ var mercenaryCampGuards = {
|
||||
* Resource spots and other points of interest
|
||||
*/
|
||||
|
||||
// Mines
|
||||
function placeMine(point, centerEntity,
|
||||
function placeMine(position, centerEntity,
|
||||
decorativeActors = [
|
||||
g_Decoratives.grass, g_Decoratives.grassShort,
|
||||
g_Decoratives.rockLarge, g_Decoratives.rockMedium,
|
||||
@@ -212,15 +211,16 @@ function placeMine(point, centerEntity,
|
||||
]
|
||||
)
|
||||
{
|
||||
placeObject(point.x, point.y, centerEntity, 0, randomAngle());
|
||||
placeObject(position, centerEntity, 0, randomAngle());
|
||||
|
||||
let quantity = randIntInclusive(11, 23);
|
||||
let dAngle = 2 * Math.PI / quantity;
|
||||
for (let i = 0; i < quantity; ++i)
|
||||
{
|
||||
let angle = dAngle * randFloat(i, i + 1);
|
||||
let dist = randFloat(2, 5);
|
||||
placeObject(point.x + dist * Math.cos(angle), point.y + dist * Math.sin(angle), pickRandom(decorativeActors), 0, randomAngle());
|
||||
}
|
||||
placeObject(
|
||||
Vector2D.add(position, new Vector2D(randFloat(2, 5), 0).rotate(-dAngle * randFloat(i, i + 1))),
|
||||
pickRandom(decorativeActors),
|
||||
0,
|
||||
randomAngle());
|
||||
}
|
||||
|
||||
// Groves, only Wood
|
||||
@@ -238,7 +238,9 @@ function placeGrove(point,
|
||||
groveTerrainTexture = getArray(g_Terrains.forestFloor1)
|
||||
)
|
||||
{
|
||||
placeObject(point.x, point.y, pickRandom(["structures/gaul_outpost", "gaia/flora_tree_oak_new"]), 0, randomAngle());
|
||||
let position = new Vector2D(point.x, point.y);
|
||||
placeObject(position, pickRandom(["structures/gaul_outpost", "gaia/flora_tree_oak_new"]), 0, randomAngle());
|
||||
|
||||
let quantity = randIntInclusive(20, 30);
|
||||
let dAngle = 2 * Math.PI / quantity;
|
||||
for (let i = 0; i < quantity; ++i)
|
||||
@@ -249,15 +251,15 @@ function placeGrove(point,
|
||||
if (i % 3 == 0)
|
||||
objectList = groveActors;
|
||||
|
||||
let position = Vector2D.add(point, new Vector2D(dist, 0).rotate(-angle));
|
||||
placeObject(position.x, position.y, pickRandom(objectList), 0, randomAngle());
|
||||
let pos = Vector2D.add(position, new Vector2D(dist, 0).rotate(-angle));
|
||||
placeObject(pos, pickRandom(objectList), 0, randomAngle());
|
||||
|
||||
let painters = [new TerrainPainter(groveTerrainTexture)];
|
||||
if (groveTileClass)
|
||||
painters.push(new TileClassPainter(groveTileClass));
|
||||
|
||||
createArea(
|
||||
new ClumpPlacer(5, 1, 1, 1, position),
|
||||
new ClumpPlacer(5, 1, 1, 1, pos),
|
||||
painters);
|
||||
}
|
||||
}
|
||||
@@ -320,7 +322,7 @@ for (let i = 0; i < num; ++i)
|
||||
fences.push(new Fortress("fence", clone(fences[i].wall).reverse()));
|
||||
|
||||
// Camps with fire and gold treasure
|
||||
function placeCamp(point,
|
||||
function placeCamp(position,
|
||||
centerEntity = "actor|props/special/eyecandy/campfire.xml",
|
||||
otherEntities = ["gaia/special_treasure_metal", "gaia/special_treasure_standing_stone",
|
||||
"units/brit_infantry_slinger_b", "units/brit_infantry_javelinist_b", "units/gaul_infantry_slinger_b", "units/gaul_infantry_javelinist_b", "units/gaul_champion_fanatic",
|
||||
@@ -328,14 +330,15 @@ function placeCamp(point,
|
||||
]
|
||||
)
|
||||
{
|
||||
placeObject(point.x, point.y, centerEntity, 0, randomAngle());
|
||||
placeObject(position, centerEntity, 0, randomAngle());
|
||||
|
||||
let quantity = randIntInclusive(5, 11);
|
||||
let dAngle = 2 * Math.PI / quantity;
|
||||
for (let i = 0; i < quantity; ++i)
|
||||
{
|
||||
let angle = dAngle * randFloat(i, i + 1);
|
||||
let dist = randFloat(1, 3);
|
||||
placeObject(point.x + dist * Math.cos(angle), point.y + dist * Math.sin(angle), pickRandom(otherEntities), 0, randomAngle());
|
||||
placeObject(Vector2D.add(position, new Vector2D(dist, 0).rotate(-angle)), pickRandom(otherEntities), 0, randomAngle());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,7 +365,7 @@ function placeStartLocationResources(
|
||||
// Stone
|
||||
let dAngle = 4/9 * Math.PI;
|
||||
let angle = currentAngle + randFloat(dAngle / 4, 3 * dAngle / 4);
|
||||
placeMine({ "x": point.x + averageDistToCC * Math.cos(angle), "y": point.y + averageDistToCC * Math.sin(angle) }, g_Gaia.stoneLarge);
|
||||
placeMine(Vector2D.add(point, new Vector2D(averageDistToCC, 0).rotate(-angle)), g_Gaia.stoneLarge);
|
||||
|
||||
currentAngle += dAngle;
|
||||
|
||||
@@ -378,7 +381,7 @@ function placeStartLocationResources(
|
||||
objectList = groveActors;
|
||||
|
||||
let position = Vector2D.add(point, new Vector2D(dist, 0).rotate(-angle));
|
||||
placeObject(position.x, position.y, pickRandom(objectList), 0, randomAngle());
|
||||
placeObject(position, pickRandom(objectList), 0, randomAngle());
|
||||
createArea(
|
||||
new ClumpPlacer(5, 1, 1, 1, position),
|
||||
[
|
||||
@@ -392,7 +395,7 @@ function placeStartLocationResources(
|
||||
// Metal
|
||||
dAngle = 4/9 * Math.PI;
|
||||
angle = currentAngle + randFloat(dAngle / 4, 3 * dAngle / 4);
|
||||
placeMine({ "x": point.x + averageDistToCC * Math.cos(angle), "y": point.y + averageDistToCC * Math.sin(angle) }, g_Gaia.metalLarge);
|
||||
placeMine(Vector2D.add(point, new Vector2D(averageDistToCC, 0).rotate(-angle)), g_Gaia.metalLarge);
|
||||
currentAngle += dAngle;
|
||||
|
||||
// Berries and domestic animals
|
||||
@@ -402,7 +405,7 @@ function placeStartLocationResources(
|
||||
{
|
||||
angle = currentAngle + randFloat(0, dAngle);
|
||||
let dist = getRandDist();
|
||||
placeObject(point.x + dist * Math.cos(angle), point.y + dist * Math.sin(angle), pickRandom(foodEntities), 0, randomAngle());
|
||||
placeObject(Vector2D.add(point, new Vector2D(dist, 0).rotate(-angle)), pickRandom(foodEntities), 0, randomAngle());
|
||||
currentAngle += dAngle;
|
||||
}
|
||||
}
|
||||
@@ -580,7 +583,7 @@ for (let h = 0; h < heighLimits.length; ++h)
|
||||
g_Map.setTexture(point, texture);
|
||||
|
||||
if (actor)
|
||||
placeObject(point.x + randFloat(0, 1), point.y + randFloat(0, 1), actor, 0, randomAngle());
|
||||
placeObject(Vector2D.add(point, new Vector2D(randFloat(0, 1), randFloat(0, 1))), actor, 0, randomAngle());
|
||||
}
|
||||
Engine.SetProgress(80);
|
||||
|
||||
@@ -588,7 +591,8 @@ log("Placing resources...");
|
||||
let avoidPoints = clone(startLocations);
|
||||
for (let i = 0; i < avoidPoints.length; ++i)
|
||||
avoidPoints[i].dist = 30;
|
||||
let resourceSpots = getPointsByHeight(resourceSpotHeightRange, avoidPoints, clPath);
|
||||
let resourceSpots = getPointsByHeight(resourceSpotHeightRange, avoidPoints, clPath).map(point => new Vector2D(point.x, point.y));
|
||||
|
||||
Engine.SetProgress(55);
|
||||
|
||||
log("Placing players...");
|
||||
@@ -597,7 +601,7 @@ if (isNomad())
|
||||
else
|
||||
for (let p = 0; p < playerIDs.length; ++p)
|
||||
{
|
||||
let point = startLocations[p];
|
||||
let point = new Vector2D(startLocations[p].x, startLocations[p].y);
|
||||
placeCivDefaultStartingEntities(point, playerIDs[p], g_Map.size > 192);
|
||||
placeStartLocationResources(point);
|
||||
}
|
||||
@@ -628,7 +632,7 @@ for (let i = 0; i < resourceSpots.length; ++i)
|
||||
}
|
||||
else
|
||||
{
|
||||
placeCustomFortress(resourceSpots[i].x, resourceSpots[i].y, pickRandom(fences), "other", 0, randomAngle());
|
||||
placeCustomFortress(resourceSpots[i], pickRandom(fences), "other", 0, randomAngle());
|
||||
rectangularSmoothToHeight(resourceSpots[i], 10, 10, g_Map.getHeight(resourceSpots[i]), 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user