forked from Mirrors/openclonk
352 lines
9.8 KiB
C
352 lines
9.8 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()
|
|
{
|
|
// Show wealth in HUD.
|
|
GUI_Controller->ShowWealth();
|
|
|
|
// 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);
|
|
goal.Picture = Krakatoa_GoalIcon;
|
|
goal.PictureName = Format("%d", SCENPAR_Difficulty);
|
|
|
|
// Some rules.
|
|
CreateObject(Rule_TeamAccount);
|
|
CreateObject(Rule_BuyAtFlagpole);
|
|
|
|
// 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);
|
|
|
|
// When rejoining, try joining at a flag. The default position may
|
|
// otherwise be on the wrong side of the volcano.
|
|
var flag = FindObject(Find_ID(Flagpole));
|
|
|
|
// 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);
|
|
if (flag)
|
|
crew->SetPosition(flag->GetX(), flag->GetY());
|
|
}
|
|
|
|
// 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(Airplane), 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(100 - dark, 100 - dark, 100 - dark);
|
|
|
|
// Time of days and celestials.
|
|
var time = CreateObject(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, Shape->Rectangle(0, hgt / 2, wdt / 2, hgt / 2), { terraform = false });
|
|
LargeCaveMushroom->Place(12 + 4 * map_size, Shape->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;
|
|
}
|
|
|
|
protected func OnGoalsFulfilled()
|
|
{
|
|
// Give the remaining players their achievement.
|
|
GainScenarioAchievement("Done", BoundBy(SCENPAR_Difficulty, 1, 3));
|
|
return false;
|
|
}
|
|
|
|
|
|
/*-- 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));
|
|
if (lava) 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("Environment::Disasters::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("Environment::Disasters::Earthquake", true, 100, nil, -1);
|
|
Sound("Environment::Disasters::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;
|
|
}
|