openclonk/planet/Arena.ocf/DarkMine.ocs/Map.c

237 lines
7.9 KiB
C

/**
Dark Mine
A single large cave surrounded by lots of small caves, connected through
narrow mine shafts.
@authors Maikel
*/
#include Library_Map
// List for storing the different large caves.
static cave_list;
// Called be the engine: draw the complete map here.
protected func InitializeMap(proplist map)
{
// Map size: all other settings depend on this value.
// The map size depends on the number of players.
var plr_cnt = GetStartupPlayerCount() - 2;
var map_size = BoundBy(140 + plr_cnt * 6, 140, 240);
// Set the map size, which is always square.
map->Resize(map_size, map_size);
// The map consists of one large cave, multiple small caves and connections.
var large_cave = FindLargeCave(map, BoundBy(map_size / 8, 18, 24));
var small_caves = FindSmallCaves(map, large_cave, map_size / 4);
var connections = FindCaveConnections(small_caves, BoundBy(map_size / 5, 24, 36));
// Store small cave positions in a static variable for the scenario script.
cave_list = [];
for (var cave in small_caves)
PushBack(cave_list, [cave.X, cave.Y]);
// Draw the background materials for the whole map.
DrawBackground();
// Draw the smaller caves.
DrawSmallCaves(small_caves);
// Draw the connections
DrawConnections(connections);
// Draw the large caves, last because they should be drawn over the
// small caves functioning as entrances.
DrawLargeCave(large_cave);
// Return true to tell the engine a map has been successfully created.
return true;
}
/*-- Cave Creation --*/
// Returns the large cave in the center of the map.
public func FindLargeCave(proplist map, int size)
{
// Get the map coordinates.
var x = map.Wdt / 2;
var y = map.Hgt / 2;
var cave = {Algo = MAPALGO_Ellipsis, X = x, Y = y, Wdt = size, Hgt = 2 * size / 3};
return cave;
}
public func FindSmallCaves(proplist map, proplist large_cave, int nr_caves)
{
// Prepare a mask out of the map and the large cave in which to search for smaller ones.
var mask = map->CreateLayer();
mask->Draw("Rock");
// Contruct the doughnut like shape in which the small caves may be found.
var x = map.Wdt / 2;
var y = map.Hgt / 2;
mask->Draw("Tunnel", {Algo = MAPALGO_Ellipsis, X = x, Y = y, Wdt = 24, Hgt = 24});
mask->Draw("Tunnel", {Algo = MAPALGO_Not, Op = {Algo = MAPALGO_Ellipsis, X = x, Y = y, Wdt = x - 2, Hgt = y - 2}});
mask->Draw("Tunnel", {Algo = MAPALGO_Ellipsis, X = large_cave.X, Y = large_cave.Y, Wdt = 3 * large_cave.Wdt / 2, Hgt = 14 * large_cave.Hgt / 10});
// Array for the small caves.
var caves = [];
// Add caves for the exit points of the large caves.
PushBack(caves, {X = large_cave.X - large_cave.Wdt - 1, Y = large_cave.Y, block_dir = COMD_Right});
PushBack(caves, {X = large_cave.X + large_cave.Wdt + 1, Y = large_cave.Y, block_dir = COMD_Left});
PushBack(caves, {X = large_cave.X, Y = large_cave.Y - large_cave.Hgt - 1, block_dir = COMD_Down});
PushBack(caves, {X = large_cave.X, Y = large_cave.Y + large_cave.Hgt + 1, block_dir = COMD_Up});
// Add caves at random locations around the map.
var border = 6;
var cave_dist = 20;
for (var i = 0; i < nr_caves; i++)
{
var cave = {};
if (!mask->FindPosition(cave, "Rock", [border, border, map.Wdt - border * 2, map.Hgt - border * 2]))
continue;
mask->Draw("Tunnel", {Algo = MAPALGO_Ellipsis, X = cave.X, Y = cave.Y, Wdt = cave_dist, Hgt = cave_dist});
PushBack(caves, cave);
}
return caves;
}
public func FindCaveConnections(array small_caves, int max_length)
{
var connections = [];
for (var cave in small_caves)
cave.conn_count = 0;
for (var i = 0; i < GetLength(small_caves) - 1; i++)
{
var from_cave = small_caves[i];
for (var j = i + 1; j < GetLength(small_caves); j++)
{
var to_cave = small_caves[j];
// Check for the maximum connections per cave.
if (from_cave.conn_count >= 4 || to_cave.conn_count >= 4)
continue;
// Cave line parameters.
var fx = from_cave.X;
var fy = from_cave.Y;
var tx = to_cave.X;
var ty = to_cave.Y;
// Check for the maximum line distance.
if (Distance(fx, fy, tx, ty) > max_length)
continue;
// Check for block line directions.
if (from_cave.block_dir != nil && IsBlockedDirection(from_cave.block_dir, fx, fy, tx, ty))
continue;
if (to_cave.block_dir != nil && IsBlockedDirection(to_cave.block_dir, tx, ty, fx, fy))
continue;
// Check for overlap in existing connections.
var has_overlap = false;
for (var line in connections)
if (IsLineOverlap(fx, fy, tx, ty, line.X[0], line.Y[0], line.X[1], line.Y[1]))
{
has_overlap = true;
break;
}
if (has_overlap)
continue;
// Determine tunnel width and make the tunnel.
var tunnel_wdt = 3;
if (!Random(10))
tunnel_wdt = 2;
var tunnel = {Algo = MAPALGO_Polygon, X = [fx, tx], Y = [fy, ty], Wdt = tunnel_wdt, Open = 1, Empty = 1};
PushBack(connections, tunnel);
small_caves[i].conn_count++;
small_caves[j].conn_count++;
}
}
return connections;
}
public func IsBlockedDirection(int dir, int x1, int y1, int x2, int y2)
{
// Use COMD dir constants.
if (dir == COMD_Right && x2 > x1)
return true;
if (dir == COMD_Left && x2 < x1)
return true;
if (dir == COMD_Down && y2 > y1)
return true;
if (dir == COMD_Up && y2 < y1)
return true;
return false;
}
/*-- Map Drawing --*/
public func DrawBackground()
{
Draw("Rock");
DrawVariations("Rock", 50, 5, 15);
DrawVariations("Ore", 10, 8, 8);
DrawVariations("Firestone", 8, 12, 3);
DrawVariations("Earth", 3, 8, 3);
DrawVariations("Earth-earth", 3, 8, 3);
DrawVariations("Earth-earth", 3, 8, 3);
DrawVariations("Earth-earth_root", 3, 8, 3);
DrawVariations("Earth-earth_spongy", 3, 8, 3);
DrawVariations("Firestone", 6, 12, 3);
DrawVariations("Coal", 8, 8, 3);
DrawVariations("Gold", 5, 4, 4);
DrawVariations("Granite", 14, 15, 5);
DrawVariations("Granite", 14, 5, 15);
return true;
}
public func DrawLargeCave(proplist large_cave)
{
// Draw the first large cave and then duplicate the others.
var cave_border = {Algo = MAPALGO_Border, Left = 5, Right = 5, Bottom = 3, Top = 5, Op = large_cave};
var border_holes = {Algo = MAPALGO_Rect, X = large_cave.X - large_cave.Wdt, Y = large_cave.Y - 1, Wdt = 2 * large_cave.Wdt, Hgt = 5};
border_holes = {Algo = MAPALGO_Or, Op = [border_holes, {Algo = MAPALGO_Rect, X = large_cave.X - 2, Y = large_cave.Y - large_cave.Hgt, Wdt = 5, Hgt = 2 * large_cave.Hgt}]};
cave_border = {Algo = MAPALGO_And, Op = [cave_border, {Algo = MAPALGO_Not, Op = border_holes}]};
var lower_half = {Algo = MAPALGO_Rect, X = large_cave.X - large_cave.Wdt, Y = large_cave.Y + 6, Wdt = 2 * large_cave.Wdt, Hgt = large_cave.Hgt};
lower_half = {Algo = MAPALGO_And, Op = [large_cave, lower_half]};
// Fill all the algorithms.
Draw("Tunnel", large_cave);
DrawMaterial("Tunnel-brickback", large_cave, 3, 30);
Draw("Earth", lower_half);
DrawMaterial("Earth-earth", lower_half, 3, 20);
DrawMaterial("Earth-earth", lower_half, 3, 20);
DrawMaterial("Earth-earth_root", lower_half, 3, 20);
DrawMaterial("Ore", lower_half, 3, 20);
DrawMaterial("Firestone", lower_half, 3, 20);
DrawMaterial("Coal", lower_half, 3, 20);
Draw("Granite", cave_border);
return;
}
public func DrawSmallCaves(array small_caves)
{
for (var cave in small_caves)
{
var cave_algo = {Algo = MAPALGO_Ellipsis, X = cave.X, Y = cave.Y, Wdt = RandomX(4, 6), Hgt = RandomX(4, 6)};
var turb_cave = {Algo = MAPALGO_Turbulence, Amplitude = 12, Scale = 8, Op = cave_algo};
Draw("Tunnel", turb_cave);
DrawMaterial("Tunnel-brickback", turb_cave, 2, 15);
}
return;
}
public func DrawConnections(connections)
{
for (var con in connections)
{
con = {Algo = MAPALGO_Turbulence, Amplitude = 5, Scale = 3, Op = con};
Draw("Tunnel", con);
DrawMaterial("Tunnel-brickback", con, 2, 15);
}
return;
}
/*-- Helper Functions --*/
public func DrawVariations(string mat, int ratio, int sx, int sy)
{
var rand_algo = {Algo=MAPALGO_RndChecker, Ratio = ratio, Wdt = sx, Hgt = sy};
var turb_algo = {Algo=MAPALGO_Turbulence, Amplitude = 12, Scale = 8, Op = rand_algo};
return Draw(mat, turb_algo);
}