openclonk/planet/Parkour.ocf/Aerobatics.ocs/Map.c

186 lines
7.1 KiB
C

/**
Aerobatics
A map with lots of small sky islands forming a parkour sequence.
@author Maikel
*/
#include Library_Map
static checkpoint_locations;
static inventorslab_location;
// Called be the engine: draw the complete map here.
public func InitializeMap(proplist map)
{
// Initialize a list for checkpoint locations.
checkpoint_locations = [];
// Determine the number of checkpoints.
var nr_checkpoints = BoundBy(SCENPAR_NrCheckPoints, 6, 20);
// Set the map size: depends on game mode and number of checkpoints.
var map_wdt = 140 + nr_checkpoints * 6;
var map_hgt = map_wdt / 2;
if (SCENPAR_GameMode == 2)
{
map_wdt = 60 + nr_checkpoints * 28;
map_hgt = 72 + nr_checkpoints * 2;
}
map->Resize(map_wdt, map_hgt);
// Determine start and finish locations.
var start_x = map.Wdt / 5;
var finish_x = 4 * map.Wdt / 5;
var middle_x = map.Wdt / 2;
var island_y = map.Hgt / 2 - 2;
if (SCENPAR_GameMode == 2)
{
start_x = 10;
finish_x = map.Wdt - 10;
}
// Draw the start platform.
DrawStartFinishIsland(map, start_x, island_y);
PushBack(checkpoint_locations, [start_x, island_y]);
// Find the checkpoint locations: substract the finish from the number of checkpoints.
var checkpoint_islands = FindCheckPointLocations(map, nr_checkpoints - 1, SCENPAR_GameMode, start_x, finish_x, middle_x, island_y);
// Store the locations in the list and draw the islands.
for (var index = 0; index < GetLength(checkpoint_islands); index++)
{
var cp_island = checkpoint_islands[index];
PushBack(checkpoint_locations, [cp_island.X, cp_island.Y]);
DrawCheckpointIsland(map, cp_island.X, cp_island.Y, index >= GetLength(checkpoint_islands) - 1 - Random(2));
}
// Draw the finish platform.
DrawStartFinishIsland(map, finish_x, island_y);
PushBack(checkpoint_locations, [finish_x, island_y]);
// Draw a platform for the inventor's lab.
DrawStartFinishIsland(map, middle_x, island_y);
inventorslab_location = [middle_x, island_y];
// Draw other smaller islands.
DrawSmallIslands(map, checkpoint_locations, start_x, finish_x, middle_x, island_y);
// Return true to tell the engine a map has been successfully created.
return true;
}
public func DrawStartFinishIsland(proplist map, int x, int y)
{
var island = {Algo = MAPALGO_Rect, X = x - 7, Y = y, Wdt = 15, Hgt = 8};
island = {Algo = MAPALGO_Or, Op = [island, {Algo = MAPALGO_Turbulence, Amplitude = 6, Scale = 6, Op = island}]};
island = {Algo = MAPALGO_And, Op = [island, {Algo = MAPALGO_Not, Op = {Algo = MAPALGO_Rect, X = x - 6, Y = y - 5, Wdt = 13, Hgt = 5}}]};
island = {Algo = MAPALGO_And, Op = [island, {Algo = MAPALGO_Not, Op = {Algo = MAPALGO_Rect, X = x - 9, Y = y - 5, Wdt = 17, Hgt = 4}}]};
Draw("Earth", island);
DrawMaterial("Firestone", island, 2, 10);
DrawMaterial("Rock", island, 2, 25);
var brick = {Algo = MAPALGO_Rect, X = x - 5, Y = y, Wdt = 11, Hgt = 2};
Draw("Brick", brick);
return;
}
public func FindCheckPointLocations(proplist map, int nr_checkpoints, int game_mode, int start_x, int finish_x, int middle_x, int island_y)
{
// Prepare a mask out of the map.
var mask = map->CreateLayer();
mask->Draw("Rock");
// Remove the start, finish and middle island from the mask.
mask->Draw("Tunnel", {Algo = MAPALGO_Ellipsis, X = start_x, Y = island_y, Wdt = 38, Hgt = 38});
mask->Draw("Tunnel", {Algo = MAPALGO_Ellipsis, X = finish_x, Y = island_y, Wdt = 38, Hgt = 38});
mask->Draw("Tunnel", {Algo = MAPALGO_Ellipsis, X = middle_x, Y = island_y, Wdt = 38, Hgt = 38});
// Remove the middle area between start and finish from the mask.
mask->Draw("Tunnel", {Algo = MAPALGO_Rect, X = start_x, Y = island_y - 16, Wdt = finish_x - start_x, Hgt = 16});
// Array for the checkpoint islands.
var checkpoint_islands = [];
// Add checkpoint islands at random locations around the map.
var border = 10;
var cp_dist_x = 28;
var cp_dist_y = 28;
// For the horizontal game mode the distance is larger.
if (game_mode == 2)
{
cp_dist_x = 42;
cp_dist_y = 30;
}
for (var i = 0; i < nr_checkpoints; i++)
{
var cp_island = {};
if (!mask->FindPosition(cp_island, "Rock", [border, border, map.Wdt - border * 2, map.Hgt - border * 2]))
{
Log("WARNING: Map script could not find a suitable checkpoint location, there will be one checkpoint less in this round.");
continue;
}
mask->Draw("Tunnel", {Algo = MAPALGO_Ellipsis, X = cp_island.X, Y = cp_island.Y, Wdt = cp_dist_x, Hgt = cp_dist_y});
PushBack(checkpoint_islands, cp_island);
}
// Sort the checkpoints horizontally if the game mode is such.
if (game_mode == 2)
{
for (var i = 1; i < GetLength(checkpoint_islands); i++)
{
var store = checkpoint_islands[i];
var j = i - 1;
while (j >= 0 && checkpoint_islands[j].X > store.X)
{
checkpoint_islands[j + 1] = checkpoint_islands[j];
j--;
}
checkpoint_islands[j + 1] = store;
}
}
return checkpoint_islands;
}
public func DrawCheckpointIsland(proplist map, int x, int y, bool enclosed)
{
var island = {Algo = MAPALGO_Rect, X = x - 4, Y = y, Wdt = 9, Hgt = 6};
island = {Algo = MAPALGO_Or, Op = [island, {Algo = MAPALGO_Turbulence, Seed = Random(65536), Amplitude = 8, Scale = 8, Op = island}]};
island = {Algo = MAPALGO_And, Op = [island, {Algo = MAPALGO_Not, Op = {Algo = MAPALGO_Rect, X = x - 4, Y = y - 5, Wdt = 9, Hgt = 5}}]};
Draw("Earth", island);
DrawMaterial("Firestone", island, 2, 10);
DrawMaterial("Rock", island, 2, 25);
var brick = {Algo = MAPALGO_Rect, X = x - 2, Y = y, Wdt = 5, Hgt = 2};
Draw("Brick", brick);
// Trap the checkpoint in rock / granite if it must be enclosed.
if (enclosed)
{
var border = {Algo = MAPALGO_Ellipsis, X = x, Y = y - 3, Wdt = 7, Hgt = 7};
border = {Algo = MAPALGO_Border, Op = border, Wdt = 2};
border = {Algo = MAPALGO_And, Op = [border, {Algo = MAPALGO_Not, Op = island}]};
Draw("Granite", border);
DrawMaterial("Rock", border, 2, 20);
}
return;
}
public func DrawSmallIslands(proplist map, array checkpoints, int start_x, int finish_x, int middle_x, int island_y)
{
// Prepare a mask out of the checkpoint positions.
var mask = {Algo = MAPALGO_Rect, X = 0, Y = 0, Wdt = 0, Hgt = 0};
var island_border = 16;
var map_border = 6;
// Remove checkpoints and middle area from mask.
for (var cp in checkpoints)
mask = {Algo = MAPALGO_Or, Op = [mask, {Algo = MAPALGO_Ellipsis, X = cp[0], Y = cp[1], Wdt = island_border, Hgt = island_border}]};
mask = {Algo = MAPALGO_Or, Op = [mask, {Algo = MAPALGO_Rect, X = start_x, Y = island_y - 16, Wdt = finish_x - start_x, Hgt = 16}]};
mask = {Algo = MAPALGO_Not, Op = mask};
mask = {Algo = MAPALGO_And, Op = [mask, {Algo = MAPALGO_Rect, X = map_border, Y = map_border, Wdt = map.Wdt - 2 * map_border, Hgt = map.Hgt - 2 * map_border}]};
// Construct the island masks.
var islands = {Algo = MAPALGO_RndChecker, Seed = Random(65536), Ratio = 4, Wdt = 4, Hgt = 3};
islands = {Algo = MAPALGO_And, Op = [islands, mask]};
islands = {Algo = MAPALGO_Or, Op = [islands, {Algo = MAPALGO_Turbulence, Seed = Random(65536), Amplitude = 6, Scale = 6, Op = islands}]};
// Draw earth and some materials.
Draw("Earth", islands);
DrawMaterial("Firestone", islands, 2, 10);
DrawMaterial("Rock", islands, 2, 25);
DrawMaterial("Ore", islands, 2, 5);
DrawMaterial("Granite", islands, 2, 5);
return;
}