/** 
	Flooded Veins
	A cave landscape where the player starts at the top and needs to retrieve some gems from
	caves filled with water.

	@author Sven2, Maikel
*/


// Whether the intro has been initialized.
static intro_init;

// Whether the first players has been initialized.
static first_plr_init;

protected func Initialize()
{
	// Show wealth in HUD.
	GUI_Controller->ShowWealth();
	
	// Rules: team account and buying at flagpole.
	CreateObject(Rule_TeamAccount);
	CreateObject(Rule_BuyAtFlagpole);
	
	// Goal: Sell a certain amount of gems dependent on difficulty.
	var goal = CreateObject(Goal_SellGems);
	goal->SetTargetAmount(10 * SCENPAR_Difficulty);

	// Initialize different parts of the scenario.
	InitEnvironment(SCENPAR_Difficulty);
	InitVegetation(SCENPAR_MapSize);
	InitAnimals(SCENPAR_MapSize, SCENPAR_Difficulty);
	return;
}

protected func OnGoalsFulfilled()
{
	// Give the remaining players their achievement.
	GainScenarioAchievement("Done", BoundBy(SCENPAR_Difficulty, 1, 3));
	return false;
}


/*-- Player Initialization --*/

protected func InitializePlayer(int plr)
{
	// Harsh zoom range.
	SetPlayerZoomByViewRange(plr, 300, nil, PLRZOOM_Direct | PLRZOOM_LimitMax);
	SetPlayerViewLock(plr, true);
	
	// First player inits the base.
	if (!first_plr_init)
	{
		InitBase(plr, 4 - SCENPAR_Difficulty);
		first_plr_init = true;
	}
	
	// Position and materials for the crew.
	var crew;
	for (var i = 0; crew = GetCrew(plr, i); ++i)
	{
		crew->SetPosition(20 + Random(32), 160 - 10);
		crew->CreateContents(Shovel);
		if (i == 0)
			crew->CreateContents(Hammer);
		else
			crew->CreateContents(Axe);
	}
	
	// Give the player basic and pumping knowledge.
	GivePlayerBasicKnowledge(plr);
	GivePlayerPumpingKnowledge(plr);
	GivePlayerSpecificKnowledge(plr, [WallKit, WindBag, TeleGlove]);
	
	// Give the player the elementary base materials.
	GivePlayerElementaryBaseMaterial(plr);
	
	// Initialize the intro sequence if not yet started.
	if (!intro_init)
	{
		StartSequence("Intro", 0);
		intro_init = true;
	}	
	return;
}

private func InitBase(int owner, int amount)
{
	var y = 160;
	
	// The basic settlement consists of a flagpole and a wind generator.
	var x = 232;
	while ((!GBackSky(x, y - 62) || !GBackSky(x, y - 66)) && x < 400)
		x++;
	CreateObjectAbove(WindGenerator, x + 4, y, owner);
	CreateObjectAbove(Flagpole, x - 24, y, owner);
	
	// Additional material includes a foundry and tools workshop.
	if (amount >= 2)
	{
		var foundry = CreateObjectAbove(Foundry, x + 38, y, owner);
		foundry->CreateContents(Coal, 4);
		foundry->CreateContents(Metal, 2);
		var workshop = CreateObjectAbove(ToolsWorkshop, x - 56, y, owner);
		workshop->CreateContents(Wood, 4);
		workshop->CreateContents(Metal, 2);
		var lorry = CreateObjectAbove(Lorry, x - 56, 155);
		
		// And even more material includes explosives and food.
		if (amount >= 3)
		{
			var chemicallab = CreateObjectAbove(ChemicalLab, x + 84, y, owner);
			chemicallab->CreateContents(Dynamite, 4);
			chemicallab->CreateContents(DynamiteBox, 4);
			workshop->CreateContents(Wood, 4);
			workshop->CreateContents(Metal, 2);
			workshop->CreateContents(Pickaxe, 1);
			lorry->CreateContents(Bread, 4);
		}
	}
	return;
}


/*-- Scenario Initialization --*/

private func InitEnvironment(int difficulty)
{
	// Sky has some parallax.
	SetSkyParallax(1, 20, 20);
	
	// Some earthquakes if difficulty prescribes it.
	if (difficulty >= 2)
		Earthquake->SetChance(4 * (difficulty - 1));
		
	// On insane difficulty the water level keeps rising.
	if (difficulty >= 3)
		AddEffect("RisingWater", nil, 100, 1);
	return;
}

global func FxRisingWaterTimer(object target, proplist effect)
{
	// Insert pixel on the water surface if there is tunnel above.
	for (var x = Random(120); x < LandscapeWidth(); x += RandomX(80, 120))
	{
		// Find first tunnel from the bottom.
		var y = LandscapeHeight();
		while (GBackSemiSolid(x, y) && y > 0)
			y -= 1;
		// Check if there is liquid below the tunnel.
		if (GBackLiquid(x, y + 2))
			InsertMaterial(Material("Water"), x, y + 4);
	}	
	return FX_OK;
}

private func InitVegetation(int map_size)
{
	var wdt = LandscapeWidth();
	var hgt = LandscapeHeight();
	
	// Cave mushrooms scattered around the top and middle sections.
	LargeCaveMushroom->Place(10, Shape->Rectangle(0, 0, wdt, hgt / 8), { terraform = false });
	LargeCaveMushroom->Place(15, Shape->Rectangle(0, hgt / 8, wdt, hgt / 8), { terraform = false });
	LargeCaveMushroom->Place(15, Shape->Rectangle(0, 2 * hgt / 8, wdt, hgt / 8), { terraform = false });
	
	// Cave entrance covered with mushrooms and bushes.
	SproutBerryBush->Place(4, Shape->Rectangle(0, 120, 100, 40));
	Fern->Place(4, Shape->Rectangle(0, 120, 100, 40));
	Mushroom->Place(6, Shape->Rectangle(0, 120, 100, 40));
	
	// The cavern has some grass wherever possible.
	PlaceGrass(100);
	
	// Entrance also location for a small cemetary.
	CreateObjectAbove(Column, 64, 160)->SetObjDrawTransform(400, 0, 0, 0, 400, 0);
	for (var x = 72; x < 104; x += RandomX(6, 14))
		CreateObjectAbove(Clonk_Grave, x, 160)->SetInscriptionMessage("R.I.P.");
	CreateObjectAbove(Column, 112, 160)->SetObjDrawTransform(400, 0, 0, 0, 400, 0);
	
	// Some ferns and mushrooms scattered around the top and middle sections.
	Fern->Place(12, Shape->Rectangle(0, 0, wdt, 3 * hgt / 8));
	Mushroom->Place(14, Shape->Rectangle(0, 0, wdt, 3 * hgt / 8));
	
	// Create earth materials in big clusters so the whole object arrangement looks a bit less uniform and more interesting.
	PlaceBatches([Firestone], 3, 100, 5);
	PlaceBatches([Rock, Loam, Loam], 10, 200, 10);
	
	// Place some underwater vegetation in the flooded caves.
	var place_rect = Shape->Rectangle(50, hgt / 2, wdt - 100, hgt / 2);
	Seaweed->Place(16 + 4 * map_size, place_rect);
	Coral->Place(16 + 8 * map_size, place_rect);
	return;
}

private func InitAnimals(int map_size, int difficulty)
{
	var wdt = LandscapeWidth();
	var hgt = LandscapeHeight();
	
	// Place some fishes and piranhas as difficulty prescribes it.
	var place_rect = Shape->Rectangle(50, hgt / 2, wdt - 100, hgt / 2);
	var fish_count = 10 + 10 * map_size;
	Fish->Place(fish_count * (3 - difficulty), place_rect);
	Piranha->Place(fish_count * (difficulty - 1), place_rect);
	return;
}


/*-- Some helper functions --*/

private func PlaceBatches(array item_ids, int n_per_batch, int batch_radius, int n_batches)
{
	// place a number (n_batches) of batches of objects of types item_ids. Each batch has n_per_batch objects.
	// fewer batches and/or objects may be placed if no space is found
	var loc, loc2, n_item_ids = GetLength(item_ids), n_created = 0, obj;
	for (var i = 0; i < n_batches; ++i)
		if (loc = FindLocation(Loc_Material("Earth")))
			for (var j = 0; j < n_per_batch; ++j)
				if (loc2 = FindLocation(Loc_InRect(loc.x - batch_radius,loc.y - batch_radius, batch_radius * 2, batch_radius * 2), Loc_Material("Earth")))
					if (obj = CreateObjectAbove(item_ids[Random(n_item_ids)], loc2.x, loc2.y))
					{
						obj->SetPosition(loc2.x, loc2.y);
						++n_created;
					}
	return n_created;
}

global func TestGemCount()
{
	var pos;
	while (pos = FindLocation(Loc_Or(Loc_Material("Ruby"), Loc_Material("Amethyst"))))
	{
		var pos = CreateObjectAbove(Rock, pos.x, pos.y)->Explode(100);
	}
	var gem_count = ObjectCount(Find_Or(Find_ID(Ruby), Find_ID(Amethyst)));
	return gem_count;
}
