/**
* @file A Constraint decides if a tile satisfies a condition defined by the class.
*/
/**
* The NullConstraint is always satisfied.
*/
function NullConstraint() {}
NullConstraint.prototype.allows = function(position)
{
return true;
};
/**
* The AndConstraint is met if every given Constraint is satisfied by the tile.
*/
function AndConstraint(constraints)
{
if (constraints instanceof Array)
this.constraints = constraints;
else if (!constraints)
this.constraints = [];
else
this.constraints = [constraints];
}
AndConstraint.prototype.allows = function(position)
{
return this.constraints.every(constraint => constraint.allows(position));
};
/**
* The OrConstraint is met if any given Constraint is satisfied by the tile.
*/
function OrConstraint(constraints)
{
if (constraints instanceof Array)
this.constraints = constraints;
else if (!constraints)
this.constraints = [];
else
this.constraints = [constraints];
}
OrConstraint.prototype.allows = function(position)
{
return this.constraints.some(constraint => constraint.allows(position));
};
/**
* The StayAreasConstraint is met if some of the given Areas contains the point.
*/
function StayAreasConstraint(areas)
{
this.areas = areas;
}
StayAreasConstraint.prototype.allows = function(position)
{
return this.areas.some(area => area.contains(position));
};
/**
* The StayAreasConstraint is met if the point is adjacent to one of the given Areas and not contained by that Area.
*/
function AdjacentToAreaConstraint(areas)
{
this.areas = areas;
}
AdjacentToAreaConstraint.prototype.allows = function(position)
{
return this.areas.some(area =>
!area.contains(position) &&
g_Map.getAdjacentPoints(position).some(adjacentPosition => area.contains(adjacentPosition)));
};
/**
* The AvoidAreasConstraint is met if none of the given Areas contain the point.
*/
function AvoidAreasConstraint(areas)
{
this.areas = areas;
}
AvoidAreasConstraint.prototype.allows = function(position)
{
return this.areas.every(area => !area.contains(position));
};
/**
* The StayTextureConstraint is met if the tile has the given texture.
*/
function StayTextureConstraint(texture)
{
this.texture = texture;
}
StayTextureConstraint.prototype.allows = function(position)
{
return g_Map.getTexture(position) == this.texture;
};
/**
* The AvoidTextureConstraint is met if the terrain texture of the tile is different from the given texture.
*/
function AvoidTextureConstraint(texture)
{
this.texture = texture;
}
AvoidTextureConstraint.prototype.allows = function(position)
{
return g_Map.getTexture(position) != this.texture;
};
/**
* The AvoidTileClassConstraint is met if there are no tiles marked with the given TileClass within the given radius of the tile.
*/
function AvoidTileClassConstraint(tileClass, distance)
{
this.tileClass = tileClass;
this.distance = distance;
}
AvoidTileClassConstraint.prototype.allows = function(position)
{
return this.tileClass.countMembersInRadius(position, this.distance) == 0;
};
/**
* The StayInTileClassConstraint is met if every tile within the given radius of the tile is marked with the given TileClass.
*/
function StayInTileClassConstraint(tileClass, distance)
{
this.tileClass = tileClass;
this.distance = distance;
}
StayInTileClassConstraint.prototype.allows = function(position)
{
return this.tileClass.countNonMembersInRadius(position, this.distance) == 0;
};
/**
* The NearTileClassConstraint is met if at least one tile within the given radius of the tile is marked with the given TileClass.
*/
function NearTileClassConstraint(tileClass, distance)
{
this.tileClass = tileClass;
this.distance = distance;
}
NearTileClassConstraint.prototype.allows = function(position)
{
return this.tileClass.countMembersInRadius(position, this.distance) > 0;
};
/**
* The BorderTileClassConstraint is met if there are
* tiles not marked with the given TileClass within distanceInside of the tile and
* tiles marked with the given TileClass within distanceOutside of the tile.
*/
function BorderTileClassConstraint(tileClass, distanceInside, distanceOutside)
{
this.tileClass = tileClass;
this.distanceInside = distanceInside;
this.distanceOutside = distanceOutside;
}
BorderTileClassConstraint.prototype.allows = function(position)
{
return this.tileClass.countMembersInRadius(position, this.distanceOutside) > 0 &&
this.tileClass.countNonMembersInRadius(position, this.distanceInside) > 0;
};
/**
* The HeightConstraint is met if the elevation of the tile is within the given range.
* One can pass Infinity to only test for one side.
*/
function HeightConstraint(minHeight, maxHeight)
{
this.minHeight = minHeight;
this.maxHeight = maxHeight;
}
HeightConstraint.prototype.allows = function(position)
{
return this.minHeight <= g_Map.getHeight(position) && g_Map.getHeight(position) <= this.maxHeight;
};
/**
* The SlopeConstraint is met if the steepness of the terrain is within the given range.
*/
function SlopeConstraint(minSlope, maxSlope)
{
this.minSlope = minSlope;
this.maxSlope = maxSlope;
}
SlopeConstraint.prototype.allows = function(position)
{
return this.minSlope <= g_Map.getSlope(position) && g_Map.getSlope(position) <= this.maxSlope;
};
/**
* The StaticConstraint is used for performance improvements of existing Constraints.
* It is evaluated for the entire map when the Constraint is created.
* So when a createAreas or createObjectGroups call uses this, it can rely on the cache,
* rather than reevaluating it for every randomized coordinate.
* Account for the fact that the cache is never updated!
*/
function StaticConstraint(constraints)
{
let mapSize = g_Map.getSize();
this.constraint = new AndConstraint(constraints);
this.cache = new Array(mapSize).fill(0).map(() => new Uint8Array(mapSize));
}
StaticConstraint.prototype.allows = function(position)
{
if (!this.cache[position.x][position.y])
this.cache[position.x][position.y] = this.constraint.allows(position) ? 2 : 1;
return this.cache[position.x][position.y] == 2;
};
/**
* Constrains the area to any tile on the map that is passable.
*/
function PassableMapAreaConstraint()
{
}
PassableMapAreaConstraint.prototype.allows = function(position)
{
return g_Map.validTilePassable(position);
};