openclonk/planet/Worlds.ocf/Krakatoa.ocs/Script.c

336 lines
9.3 KiB
C

/**
Krakatoa's Krach
Players are challenged to build up a settlement on top of an active volcano
after their airplane crashed. They need to gather gold from the core of the
volcano to show your skills of entering a volcano. The gold bars need to be
transported out by a newly constructed airplane.
@author Maikel
*/
// Whether the intro has been initialized.
static intro_init;
protected func Initialize()
{
// Goal: construct an airplane and fill it with gold bars.
var goal = CreateObject(Goal_Script);
// Add an effect to check whether the goal is fulfilled.
var effect = AddEffect("GoalCheck", nil, 100, 2, nil);
effect.goal = goal;
effect.barcnt = 8 * SCENPAR_Difficulty;
// Set goal name and description.
goal.Name = "$GoalName$";
goal.Description = Format("$GoalDesc$", effect.barcnt);
// Some rules.
CreateObject(Rule_TeamAccount);
CreateObject(Rule_BuyAtFlagpole);
CreateObject(Rule_StructureHPBars);
// Rescale chasm exits.
var map_zoom = GetScenarioVal("MapZoom", "Landscape");
for (var i = 0; i < 5; i++)
for (var j = 0; j < 2; j++)
chasm_exits[i][j] *= map_zoom;
// Initialize different parts of the scenario.
InitEnvironment(SCENPAR_Difficulty);
InitVegetation(SCENPAR_MapSize);
InitAnimals();
InitMaterial(4 - SCENPAR_Difficulty);
return;
}
/*-- Player Initialization --*/
protected func InitializePlayer(int plr)
{
// Set zoom range.
SetPlayerZoomByViewRange(plr, 500, nil, PLRZOOM_Direct | PLRZOOM_LimitMax);
SetPlayerViewLock(plr, true);
// Give the player its knowledge and base materials.
GivePlayerBasicKnowledge(plr);
GivePlayerPumpingKnowledge(plr);
GivePlayerAdvancedKnowledge(plr);
GivePlayerArtilleryKnowledge(plr);
GivePlayerAirKnowledge(plr);
// Give the player the elementary base materials.
GivePlayerElementaryBaseMaterial(plr);
// Give crew some equipment.
var index = 0, crew;
while (crew = GetCrew(plr, index++))
{
if (index == 1)
crew->CreateContents(Hammer);
if (index == 2)
crew->CreateContents(Axe);
crew->CreateContents(Shovel);
}
// Initialize the intro sequence if not yet started.
if (!intro_init)
{
StartSequence("Intro", 0, SCENPAR_Difficulty);
intro_init = true;
// Give only the first joined player some wealth.
SetWealth(plr, 75 - 25 * SCENPAR_Difficulty);
}
return;
}
/*-- Goal Check --*/
global func FxGoalCheckTimer(object target, proplist effect)
{
// Complete goal if there is an airplane with the required amount of gold bars.
for (var plane in FindObjects(Find_ID(Plane), Find_Not(Find_Func("IsBroken"))))
{
if (plane->ContentsCount(GoldBar) >= effect.barcnt)
{
if (effect.goal)
effect.goal->Fulfill();
return -1;
}
}
return 1;
}
/*-- Scenario Initialization --*/
private func InitEnvironment(int difficulty)
{
// Adjust the mood, orange sky, darker feeling in general.
var dark = 10;
SetSkyAdjust(RGB(150, 42, 0));
SetGamma(RGB(0, 0, 0), RGB(128 - dark, 128 - dark, 128 - dark), RGB(255 - 2 * dark, 255 - 2 * dark, 255 - 2 * dark));
// Time of days and celestials.
CreateObject(Environment_Celestial);
var time = CreateObject(Environment_Time);
time->SetTime(60 * 20);
time->SetCycleSpeed(20);
// Some dark clouds which rain few ashes.
Cloud->Place(15);
Cloud->SetPrecipitation("Ashes", 10 * difficulty);
// Some natural disasters, earthquakes, volcanos, meteorites.
Meteor->SetChance(2 + 4 * difficulty);
if (difficulty >= 2)
Earthquake->SetChance(6 * difficulty);
// Initialize the effect for controlling the big volcano.
var effect = AddEffect("BigVolcano", nil, 100, 5, nil);
effect.difficulty = difficulty;
return;
}
private func InitVegetation(int map_size)
{
var wdt = LandscapeWidth();
var hgt = LandscapeHeight();
// Place some trees, rather with leaves.
var veg;
for (var i = 0; i < 20 + Random(4); i++)
PlaceVegetation(Tree_Coconut, 0, 0, wdt, hgt, 1000 * (61 + Random(40)));
// Create an effect to make sure there will always grow some new trees.
AddEffect("EnsureTrees", nil, 100, 20, nil);
// Some large cave mushrooms, equals amounts on both sides.
LargeCaveMushroom->Place(12 + 4 * map_size, Rectangle(0, hgt / 2, wdt / 2, hgt / 2), { terraform = false });
LargeCaveMushroom->Place(12 + 4 * map_size, Rectangle(wdt / 2, hgt / 2, wdt / 2, hgt / 2), { terraform = false });
// Some dead tree trunks.
for (var i = 0; i < 16 + Random(4); i++)
{
veg = PlaceVegetation(Trunk, 0, 0, LandscapeWidth(), hgt, 1000 * (61 + Random(20)));
if (veg)
veg->SetR(RandomX(-20, 20));
}
// Some mushrooms as source of food.
Mushroom->Place(22 + Random(8));
// Some ferns, to be burned soon.
Fern->Place(25 + Random(5));
// Branches as a nice additional source of wood.
Branch->Place(30 + Random(8));
// Some objects in the earth.
PlaceObjects(Rock, 30 + 15 * map_size + Random(10),"Earth");
PlaceObjects(Firestone, 40 + 15 * map_size + Random(5), "Earth");
PlaceObjects(Loam, 30 + 15 * map_size + Random(5), "Earth");
return;
}
private func InitAnimals()
{
return;
}
private func InitMaterial(int amount)
{
return;
}
// Ensures that there will always grow some trees.
global func FxEnsureTreesTimer()
{
// Place a tree if there are less than eight trees, with increasing likelihood for lower amounts of trees.
var nr_trees = ObjectCount(Find_Func("IsTree"), Find_ID(Tree_Coconut));
if (Random(9) >= nr_trees)
if (!Random(20))
PlaceVegetation(Tree_Coconut, 0, 0, LandscapeWidth(), LandscapeHeight(), 3);
return FX_OK;
}
/*-- Volcano Effect --*/
// The volcano will do two types of eruptions:
// Smaller ones where just some lava is flowing out of the chasms.
// Bigger ones with chunks, ashes, rocks, explosions, etc.
global func FxBigVolcanoStart(object target, proplist effect, int temporary)
{
if (temporary)
return FX_OK;
// Ensure right effect interval.
effect.Interval = 5;
return FX_OK;
}
global func FxBigVolcanoTimer(object target, proplist effect)
{
// Insert some lava in the big body of lava in the core of the volcano.
// Find a surface on which we can release some lava pixels and bubbles.
/*for (var x = Random(250); x < LandscapeWidth(); x += RandomX(200, 300))
{
// Find first tunnel from the bottom.
var y = LandscapeHeight();
while (GBackSemiSolid(x, y) && y > 0)
y -= 2;
// Check if there is liquid below the tunnel.
if (GBackLiquid(x, y + 4))
{
InsertMaterial(Material("DuroLava"), x, y + 4);
}
}*/
// Some bubles in the lava.
// TODO
// Some small fountains at random locations in the different chasms.
for (var i = 0; i < 5; i++)
{
var pos = chasm_exits[i];
var lava = FindLocation(Loc_Material("DuroLava"), Loc_InRect(pos[0] - 100, pos[1] - 100, 200, 200));
InsertMaterial(Material("DuroLava"), lava.x, lava.y);
}
// At more rare occasions there will be a bigger eruption with chunks.
if (!Random(1200 - 200 * effect.difficulty) && false)
{
// Find the location to erupt from the chasm_exit.
var pos = chasm_exits[0];
var x = pos[0];
var y = pos[1];
var at_lava = GBackLiquid(x, y);
if (at_lava)
while (GBackLiquid(x, y) && y > 0)
y--;
else
while (!GBackLiquid(x, y) && y < LandscapeHeight())
y++;
// Check if there is enough room for an eruption.
if (GBackLiquid(x - 5, y + 8) && GBackLiquid(x + 5, y + 8) && !GBackSemiSolid(x - 5, y - 8) && !GBackSemiSolid(x + 5, y - 8))
{
// Launch a big eruption from this location.
AddEffect("BigEruption", nil, 100, 1, nil, nil, x, y - 2);
}
}
return FX_OK;
}
global func FxBigEruptionStart(object target, proplist effect, int temporary, int x, int y)
{
if (temporary)
return FX_OK;
// Ensure right effect interval.
effect.Interval = 1;
// Take over launch coordinates.
effect.X = x;
effect.Y = y;
// Duration of 6-9 seconds.
effect.Duration = (6 + Random(4)) * 36;
// Use earthquake sound for this eruption.
Sound("Earthquake", true, 100, nil, 1);
// Shake also the viewport a bit on a big eruption.
ShakeViewport(3200, x, y);
return FX_OK;
}
global func FxBigEruptionTimer(object target, proplist effect, int time)
{
// Eruption lasts for some time.
if (time > effect.Duration)
return FX_Execute_Kill;
// Cast some lava and ashes pixels at surface.
for (var i = 0; i < 3; i++)
{
var x = effect.X + RandomX(-80, 80);
var y = effect.Y + 5;
while (GBackLiquid(x, y))
y--;
CastPXS("DuroLava", 2, 120 + Random(40), x, y - 2, 0, 40);
if (!Random(4))
{
CastPXS("Ashes", 2, 120 + Random(40), x, y - 2, 0, 40);
Smoke(x, y, 8 + Random(4));
}
}
// Throw around some lava chunks.
if (!Random(6))
{
var angw = 40, lev = 120;
var obj = CreateObjectAbove(LavaChunk, effect.X + RandomX(-5, 5), effect.Y, NO_OWNER);
var ang = - 90 + RandomX(-angw / 2, angw / 2);
var xdir = Cos(ang, lev) + RandomX(-3, 3);
obj->SetR(Random(360));
obj->SetXDir(xdir);
obj->SetYDir(Sin(ang, lev) + RandomX(-3, 3));
obj->SetRDir(-10 + Random(21));
obj->DoCon(RandomX(-20,40));
}
// Some lava glow and smoke through particles.
return FX_OK;
}
global func FxBigEruptionStop(object target, proplist effect, int reason, bool temporary)
{
if (temporary)
return FX_OK;
// Stop eruption sound.
Sound("Earthquake", true, 100, nil, -1);
Sound("EarthquakeEnd",true);
return FX_OK;
}
/*-- Helper functions --*/
global func TestGoldCount()
{
var pos;
while (pos = FindLocation(Loc_Material("Gold")))
{
var pos = CreateObjectAbove(Rock, pos.x, pos.y)->Explode(100);
}
var gold_count = ObjectCount(Find_ID(Nugget));
return gold_count;
}