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

262 lines
7.5 KiB
C

/**
Dark Mine
Dark caves with narrow connections set the stage for this battle. Every player
only has a single clonk and no relaunches, so caution is needed.
@author Maikel
*/
// List for storing the different large caves.
static cave_list;
protected func Initialize()
{
// Goals and rules.
CreateObject(Goal_LastManStanding);
CreateObject(Rule_KillLogs);
CreateObject(Rule_Gravestones);
// Rescale cave coordinates with map zoom and shuffle them.
var mapzoom = GetScenarioVal("MapZoom", "Landscape");
for (var cave in cave_list)
{
cave[0] *= mapzoom;
cave[1] *= mapzoom;
}
ShuffleArray(cave_list);
// Then add a nil entry at position one as a separator.
PushFront(cave_list, nil);
// Initialize different parts of the scenario.
// Amount of things depends on the map size.
var plr_cnt = GetStartupPlayerCount();
var map_size = BoundBy(120 + plr_cnt * 10, 140, 240);
InitVegetation(map_size);
InitMaterials(map_size);
InitEnvironment(map_size);
InitLorries();
return;
}
// Callback from the last man standing goal.
protected func RelaunchCount()
{
// Relaunch count depends on scenario setting.
return BoundBy(SCENPAR_NrRelaunches, 0, 3);
}
// Callback from the last man standing goal.
protected func KillsToRelaunch()
{
// No relaunches awarded for kills.
return 0;
}
// Callback from the last man standing goal.
// Takes over the role of initializing the player.
protected func OnPlayerRelaunch(int plr, int relaunch_cnt)
{
var is_relaunch = relaunch_cnt != RelaunchCount();
// Get the only clonk of the player.
var clonk = GetCrew(plr);
// Players start in a random small cave, the cave depends on whether it is a relaunch.
var cave = FindStartCave(plr, is_relaunch);
clonk->SetPosition(cave[0], cave[1]);
// Players start with a shovel, a pickaxe and two firestones.
clonk->CreateContents(Shovel);
clonk->CreateContents(Pickaxe);
clonk->CreateContents(Torch);
// Better weapons after relaunching.
if (!is_relaunch)
{
clonk->CreateContents(Firestone, 2);
}
else
{
clonk->CreateContents(Javelin);
clonk->CreateContents(BombArrow);
}
// Set the zoom range to be standard low, but allow for zooming out
// such that light sources a bit further away can be spotted.
SetPlayerZoomByViewRange(plr, 300, nil, PLRZOOM_Direct);
SetPlayerZoomByViewRange(plr, 600, nil, PLRZOOM_LimitMax);
SetPlayerViewLock(plr, true);
return;
}
// Finds a start cave which is furthest away from the center and from other already used start caves.
private func FindStartCave(int plr, bool is_relaunch)
{
var wdt = LandscapeWidth() / 2;
var hgt = LandscapeHeight() / 2;
// Find the already used caves.
var used_caves = [];
var index_av;
for (index_av = 0; index_av < GetLength(cave_list); index_av++)
{
if (cave_list[index_av] == nil)
break;
PushBack(used_caves, cave_list[index_av]);
}
// Then iterate over all still available caves and find the one furthest away from all other caves.
var best_index;
var max_dist = 0;
for (var index = index_av + 1; index < GetLength(cave_list); index++)
{
var cave = cave_list[index];
// Also furthest away from center cave.
var dist = Distance(cave[0], cave[1], wdt, hgt);
// For a normal cave take distance to used caves, for a relaunch to alive clonks.
if (!is_relaunch)
{
for (var comp_cave in used_caves)
dist = Min(dist, Distance(cave[0], cave[1], comp_cave[0], comp_cave[1]));
}
else
{
for (var clonk in FindObjects(Find_OCF(OCF_CrewMember), Find_Not(Find_Owner(plr))))
dist = Min(dist, Distance(cave[0], cave[1], clonk->GetX(), clonk->GetY()));
}
if (dist > max_dist)
{
best_index = index;
max_dist = dist;
}
}
// If no cave has found, spawn in the large cave.
if (best_index == nil)
return [wdt, hgt];
// Determine found cave and move it in front of the separator if it is not a relaunch.
var found_cave = cave_list[best_index];
if (!is_relaunch)
{
RemoveArrayIndex(cave_list, best_index);
PushFront(cave_list, found_cave);
}
// Return the location of the found cave.
return found_cave;
}
/*-- Scenario Initiliaztion --*/
private func InitVegetation(int map_size)
{
// Place some cave mushrooms for cover.
LargeCaveMushroom->Place(map_size - 20, nil, { terraform = false });
// Some mushrooms to regain health.
Mushroom->Place(map_size / 2);
Fern->Place(map_size / 3);
// Place some branches and trunks around the map.
Branch->Place(map_size / 2);
Trunk->Place(map_size / 4, nil, { size = [60, 80] });
return;
}
private func InitMaterials(int map_size)
{
// Some objects in the earth or rock material.
PlaceObjects(Loam, map_size / 3, "Earth");
PlaceObjects(Firestone, map_size / 3, "Earth");
PlaceObjects(Dynamite, map_size / 5, "Earth");
PlaceObjects(DynamiteBox, map_size / 6, "Rock");
PlaceObjects(PowderKeg, map_size / 10, "Rock");
// Some pickaxes, shovels in the tunnels.
for (var i = 0; i < map_size / 5; i++)
{
var loc = FindLocation(Loc_Tunnel(), Loc_Wall(CNAT_Bottom));
if (!loc)
continue;
CreateObjectAbove([Shovel, Pickaxe, GoldBar][Random(3)], loc.x, loc.y)->SetR(Random(360));
}
return;
}
private func InitEnvironment(int map_size)
{
var wdt = LandscapeWidth();
var hgt = LandscapeHeight();
// Some lights in the main cave as a strategic element.
for (var side = -1; side <= 1; side += 2)
{
// Both sides of the cave are lighted for all players.
var torch = CreateObjectAbove(Torch, wdt / 2 + side * 50, hgt / 2 + 32);
torch->AttachToWall(true);
}
return;
}
private func InitLorries()
{
var wdt = LandscapeWidth();
var hgt = LandscapeHeight();
// Create lorries at random small caves, but only for half of them.
for (var index = GetLength(cave_list) - 1; index >= GetLength(cave_list) / 2; index--)
{
var cave = cave_list[index];
var lorry = CreateObjectAbove(Lorry, cave[0], cave[1]);
// Basic objects which are in every lorry.
lorry->CreateContents(Dynamite, RandomX(2, 4));
lorry->CreateContents(Loam, RandomX(2, 4));
// Objects which are only in half of the lorries.
if (!Random(2))
lorry->CreateContents(DynamiteBox, RandomX(1, 2));
if (!Random(2))
lorry->CreateContents(Shield);
if (!Random(2))
lorry->CreateContents(Torch, 2);
// Objects which are only in one third of the lorries.
if (!Random(3))
lorry->CreateContents(GrappleBow, RandomX(1, 2));
if (!Random(3))
lorry->CreateContents(Bread, RandomX(1, 2));
if (!Random(3))
{
lorry->CreateContents(Bow);
lorry->CreateContents([Arrow, FireArrow, FireArrow][Random(3)], 2);
}
// Objects which are only in one fifth of the lorries.
if (!Random(5))
lorry->CreateContents(Javelin, RandomX(1, 2));
if (!Random(5))
lorry->CreateContents(Club, RandomX(1, 2));
if (!Random(5))
{
var barrel = lorry->CreateContents(Barrel);
barrel->SetFilled("Water", Barrel->BarrelMaxFillLevel());
}
// Objects which are only in one eighth of the lorries.
if (!Random(8))
lorry->CreateContents(IronBomb, RandomX(1, 2));
if (!Random(8))
lorry->CreateContents(WallKit, 1);
if (!Random(8))
{
lorry->CreateContents(Musket);
lorry->CreateContents(LeadShot);
}
}
// Create two lorries at the main cave.
for (var side = -1; side <= 1; side += 2)
{
// Create lorry with useful tools and weapons.
var lorry = CreateObjectAbove(Lorry, wdt / 2 + side * 50, hgt / 2 + 44);
lorry->CreateContents(Bow, 2);
lorry->CreateContents(BombArrow, 4);
lorry->CreateContents(Boompack, 2);
lorry->CreateContents(PowderKeg, 2);
lorry->CreateContents(TeleGlove, 1);
lorry->CreateContents(WindBag, 1);
lorry->CreateContents(GrenadeLauncher);
lorry->CreateContents(IronBomb, 4);
}
return;
}