/**
	Tutorial 07: Airborne Mining
	Author: Maikel
	
	Mine valuable gems from a ruby stalactite.
	
	Following controls and concepts are explained:
	 * Airship controls
	 * Rope ladders
	 * Gem materials
	 * Selling at the flagpole
*/

static guide; // guide object

protected func Initialize()
{
	// Tutorial goal.
	var goal = CreateObject(Goal_Tutorial);
	goal.Name = "$MsgGoalName$";
	goal.Description = "$MsgGoalDescription$";
	CreateObject(Rule_NoPowerNeed);
	
	// Place objects in different sections.
	InitMountain();
	InitRubyIsland();
	InitIslands();
	InitVegetation();
	InitAnimals();
	InitAI();
	
	// Environment.
	Time->Init();
	Time->SetTime(22 * 60 + 30);
	Time->SetCycleSpeed(0);
	
	// Wealth shown at all time
	GUI_Controller->ShowWealth();

	// Dialogue options -> repeat round.
	SetNextMission("Tutorials.ocf\\Tutorial07.ocs", "$MsgRepeatRound$", "$MsgRepeatRoundDesc$");
	return;
}

// Gamecall from goals, set next mission.
protected func OnGoalsFulfilled()
{
	// Achievement: Tutorial completed.
	GainScenarioAchievement("TutorialCompleted", 3);
	// Dialogue options -> next round.
	SetNextMission("Tutorials.ocf\\Tutorial08.ocs", "$MsgNextTutorial$", "$MsgNextTutorialDesc$");
	// Normal scenario ending by goal library.
	return false;
}

private func InitMountain()
{
	// Shipyard with lantern and flagpole.
	CreateObjectAbove(Flagpole, 55, 504)->MakeInvincible();
	var shipyard = CreateObjectAbove(Shipyard, 90, 504);
	shipyard->MakeInvincible();
	var lamp = shipyard->CreateContents(Lantern);
	lamp->TurnOn();
	// Indestructible airship.
	var airship = CreateObjectAbove(Airship, 120, 504);
	airship->MakeInvincible();
	// Lorry with dynamite and tools.
	var lorry = CreateObjectAbove(Lorry, 120, 498);
	for (var cnt = 0; cnt < 4; cnt ++)
	{
		var dynamite_box = lorry->CreateContents(DynamiteBox);
		dynamite_box->SetDynamiteCount(3);
	}
	lorry->CreateContents(Pickaxe);
	lorry->CreateContents(TeleGlove);
	lorry->MakeInvincible();
	return;
}

private func InitRubyIsland()
{
	// Two rope ladders give access to the ruby stalactite.
	CreateObjectAbove(Ropeladder, 740, 160)->Unroll(-1, COMD_Up);
	CreateObjectAbove(Ropeladder, 780, 160)->Unroll(-1, COMD_Up);
	return;
}

private func InitIslands()
{
	// Armory on the lower island with weaponry to kill bats.
	CreateObjectAbove(WindGenerator, 700, 648)->MakeInvincible();
	var armory = CreateObjectAbove(Armory, 654, 648);
	armory->CreateContents(Wood, 10);
	armory->CreateContents(Metal, 5);
	armory->MakeInvincible();
	// Flowers on two of the islands.
	Flower->Place(12, Rectangle(200, 100, 300, 200));
	Flower->Place(8, Rectangle(300, 300, 200, 200));
	return;
}

// Vegetation throughout the scenario.
private func InitVegetation()
{
	PlaceGrass(85);
	PlaceObjects(Firestone, 25 + Random(5), "Earth");
	PlaceObjects(Loam, 15 + Random(5), "Earth");
	Mushroom->Place(10);
	Branch->Place(40);
	Trunk->Place(10);
	Tree_Deciduous->Place(40);
	return;
}

private func InitAnimals()
{
	// The sky islands are a natural place for bats to hide. 		
	var bats = Bat->Place(6);
	// Make the bats a bit weaker so that they are killed with a single arrow.
	for (var bat in bats)
	{
		bat.MaxEnergy = 7000;
		bat->DoEnergy(bat.MaxEnergy - bat->GetEnergy());
	}
	// Some fireflies attracted to trees on two islands.
	Firefly->Place(2, nil, Rectangle(200, 100, 300, 200));
	Firefly->Place(2, nil, Rectangle(300, 300, 200, 200));
	return;
}

// Initializes the AI: which is all defined in System.ocg
private func InitAI()
{
	// A pilot npc for explaining the sky islands.
	var npc_pilot = CreateObjectAbove(Clonk, 108, 496);
	npc_pilot->SetColor(0xffff00);
	npc_pilot->SetName("Chris");
	npc_pilot->SetObjectLayer(npc_pilot);
	npc_pilot->SetSkin(2);
	npc_pilot->SetDir(DIR_Right);
	npc_pilot->SetDialogue("Pilot", true);
	return;
}

/*-- Player Handling --*/

protected func InitializePlayer(int plr)
{
	// Position player's clonk.
	var clonk = GetCrew(plr, 0);
	clonk->SetPosition(60, 494);
	var effect = AddEffect("ClonkRestore", clonk, 100, 10);
	effect.to_x = 60;
	effect.to_y = 494;
	
	// Items for the clonk.
	clonk->CreateContents(Shovel);
	var dynamite_box = clonk->CreateContents(DynamiteBox);
	dynamite_box->SetDynamiteCount(3);
	
	// Take ownership of the flags.
	for (var flag in FindObjects(Find_Or(Find_Func("IsFlagpole"), Find_ID(WindGenerator))))
		flag->SetOwner(plr);
	
	// Knowledge to construct bow and arrow.
	SetPlrKnowledge(plr, Bow);
	SetPlrKnowledge(plr, Arrow);
	
	// Add an interaction to call the airship.
	Helper_CallAirship->Create(clonk, Dialogue->FindByName("Pilot")->GetDialogueTarget(), FindObject(Find_ID(Airship)));
	
	// Add an effect to the clonk to track the goal.
	var track_goal = AddEffect("TrackGoal", nil, 100, 2);
	track_goal.plr = plr;

	// Standard player zoom for tutorials, player is not allowed to zoom in/out.
	SetPlayerViewLock(plr, true);
	SetPlayerZoomByViewRange(plr, 400, nil, PLRZOOM_Direct | PLRZOOM_LimitMax);
	
	// Determine player movement keys.
	var interact_prev = GetPlayerControlAssignment(plr, CON_InteractNext_Right, true, true);
	var interact_next = GetPlayerControlAssignment(plr, CON_InteractNext_Left, true, true);
	var interact_cycle = GetPlayerControlAssignment(plr, CON_InteractNext_CycleObject, true, true);
	var interact_cancel = GetPlayerControlAssignment(plr, CON_InteractNext_Stop, true, true);
	
	// Create tutorial guide, add messages, show first.
	guide = CreateObjectAbove(TutorialGuide, 0, 0, plr);
	guide->AddGuideMessage(Format("$MsgTutorialTalkToPilot$", interact_prev, interact_next, interact_cycle, interact_cancel));
	guide->ShowGuideMessage();
	var effect = AddEffect("TutorialTalkedToPilot", nil, 100, 2);
	effect.plr = plr;
	return;
}


/*-- Intro, Tutorial Goal & Outro --*/

global func FxTrackGoalTimer(object target, proplist effect, int time)
{
	if (GetWealth(effect.plr) >= 250)
	{
		var outro = AddEffect("GoalOutro", target, 100, 5);
		outro.plr = effect.plr;
		return FX_Execute_Kill;
	}
	return FX_OK;
}

global func FxGoalOutroStart(object target, proplist effect, int temp)
{
	if (temp)
		return FX_OK;	
	// Show guide message congratulating.
	guide->AddGuideMessage("$MsgTutorialCompleted$");
	guide->ShowGuideMessage();	
	return FX_OK;
}

global func FxGoalOutroTimer(object target, proplist effect, int time)
{
	if (time >= 60)
	{
		var goal = FindObject(Find_ID(Goal_Tutorial));
		goal->Fulfill();
		return FX_Execute_Kill;
	}
	return FX_OK;
}

global func FxGoalOutroStop(object target, proplist effect, int reason, bool temp)
{
	if (temp) 
		return FX_OK;
	return FX_OK;
}


/*-- Guide Messages --*/

public func OnHasTalkedToPilot()
{
	RemoveEffect("TutorialTalkedToPilot");
	return;
}

global func FxTutorialTalkedToPilotTimer()
{
	return FX_OK;
}

global func FxTutorialTalkedToPilotStop(object target, proplist effect, int reason, bool temp)
{
	if (temp)
		return FX_OK;

	// Determine player movement keys.
	var left = GetPlayerControlAssignment(effect.plr, CON_Left, true, true);
	var right = GetPlayerControlAssignment(effect.plr, CON_Right, true, true);
	var up = GetPlayerControlAssignment(effect.plr, CON_Up, true, true);
	var down = GetPlayerControlAssignment(effect.plr, CON_Down, true, true);
	var interact = GetPlayerControlAssignment(effect.plr, CON_Interact, true, true);
	var control_keys = Format("[%s] [%s] [%s] [%s]", up, left, down, right);
	
	guide->AddGuideMessage(Format("$MsgTutorialFindRubies$", interact, control_keys));
	guide->ShowGuideMessage();
	var new_effect = AddEffect("TutorialFoundStalactite", nil, 100, 2);
	new_effect.plr = effect.plr;
	return FX_OK;
}

global func FxTutorialFoundStalactiteTimer(object target, proplist effect, int timer)
{
	var clonk = FindObject(Find_ID(Clonk), Find_Distance(150, 780, 200));
	if (clonk)
	{
		guide->AddGuideMessage(Format("$MsgTutorialParkAirship$"));
		guide->ShowGuideMessage();
		AddEffect("TutorialAirshipParked", nil, 100, 2);
		return FX_Execute_Kill;
	}
	return FX_OK;
}

global func FxTutorialAirshipParkedTimer(object target, proplist effect, int timer)
{
	var clonk = FindObject(Find_ID(Clonk), Find_Distance(30, 688, 200));
	var airship = FindObject(Find_ID(Airship), Find_Distance(30, 688, 200));
	if (clonk && airship)
	{
		var plr = clonk->GetOwner();
		var left = GetPlayerControlAssignment(plr, CON_Left, true, true);
		var right = GetPlayerControlAssignment(plr, CON_Right, true, true);
		guide->AddGuideMessage(Format("$MsgTutorialLadderJump$", left, right));
		guide->ShowGuideMessage();
		AddEffect("TutorialOnStalactite", nil, 100, 2);
		return FX_Execute_Kill;
	}
	return FX_OK;
}

global func FxTutorialOnStalactiteTimer(object target, proplist effect, int timer)
{
	if (FindObject(Find_ID(Clonk), Find_InRect(810, 150, 24, 72)))
	{
		guide->AddGuideMessage("$MsgTutorialBlastGems$");
		guide->ShowGuideMessage();
		AddEffect("TutorialCollectGems", nil, 100, 2);
		return FX_Execute_Kill;
	}
	return FX_OK;
}

global func FxTutorialCollectGemsTimer(object target, proplist effect, int timer)
{
	if (FindObject(Find_ID(Ruby)))
	{
		guide->AddGuideMessage("$MsgTutorialCollectGems$");
		guide->ShowGuideMessage();
		return FX_Execute_Kill;
	}
	return FX_OK;
}

protected func OnGuideMessageShown(int plr, int index)
{
	// Show airship parking space.
	if (index == 2)
		TutArrowShowPos(688, 220, 135);
	// Show dynamite placement location.
	if (index == 4)
		TutArrowShowPos(800, 200, 60);	
	return;
}

protected func OnGuideMessageRemoved(int plr, int index)
{
	TutArrowClear();
	return;
}


/*-- Clonk restoring --*/

global func FxClonkRestoreTimer(object target, proplist effect, int time)
{
	// Respawn clonk to new location if reached certain position.
	return FX_OK;
}

// Relaunches the clonk, from death or removal.
global func FxClonkRestoreStop(object target, effect, int reason, bool  temporary)
{
	if (reason == 3 || reason == 4)
	{
		var restorer = CreateObject(ObjectRestorer, 0, 0, NO_OWNER);
		var x = BoundBy(target->GetX(), 0, LandscapeWidth());
		var y = BoundBy(target->GetY(), 0, LandscapeHeight());
		restorer->SetPosition(x, y);
		var to_x = effect.to_x;
		var to_y = effect.to_y;
		var airship = FindObject(Find_ID(Airship));
		if (airship)
		{
			to_x = airship->GetX();
			to_y = airship->GetY();
		}
		// Respawn new clonk.
		var plr = target->GetOwner();
		var clonk = CreateObject(Clonk, 0, 0, plr);
		clonk->GrabObjectInfo(target);
		Rule_Relaunch->TransferInventory(target, clonk);
		SetCursor(plr, clonk);
		clonk->DoEnergy(100000);
		// Add an interaction to call the airship.
		Helper_CallAirship->Create(clonk, Dialogue->FindByName("Pilot")->GetDialogueTarget(), FindObject(Find_ID(Airship)));
		restorer->SetRestoreObject(clonk, nil, to_x, to_y, 0, "ClonkRestore");
	}
	return FX_OK;
}