/** 
	Tutorial 06: Power Problems
	Author: Maikel
	
	The player has reached the friendly village high up in the skies, they don't have power as there is no wind.
	Help them setting up a back-up power supply and construct an airplane so they will fight against the evil faction.
	
	Following controls and concepts are explained:
	 * Power system and overview
	 * Buying at the flagpole
	 * Construction of steam engine and compensator
	 * Catapult (shooting objects and oneself)
	 * Production of airplane
	 
	TODO:
	 * Outro with airplane who takes the player to the next round.
	 * Intro with airship from bottom left (also add to tutorial 5).
	 * NPC clonks.
	 * Children NPCs playing with the catapults.
	 * Make a script player who is owner of the village.
*/

static guide; // guide object.

protected func Initialize()
{
	// Tutorial goal.
	var goal = CreateObject(Goal_Tutorial);
	goal.Name = "$MsgGoalName$";
	goal.Description = "$MsgGoalDescription$";

	// Enable buying at the flagpole
	CreateObject(Rule_BuyAtFlagpole);
	
	// Place objects in different sections.
	InitBottomIsland();
	InitMiddleIsland();
	InitTopIsland();
	InitVegetation();
	InitAnimals();
	InitAI();	
	
	// Dialogue options -> repeat round.
	SetNextMission("Tutorials.ocf\\Tutorial06.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\\Tutorial07.ocs", "$MsgNextTutorial$", "$MsgNextTutorialDesc$");
	// Normal scenario ending by goal library.
	return false;
}

private func InitBottomIsland()
{
	var shipyard = CreateObjectAbove(Shipyard, 250, 568);
	shipyard->MakeInvincible();
	shipyard->CreateContents(Wood, 4);
	shipyard->CreateContents(Metal, 6);
	
	CreateObjectAbove(Flagpole, 440, 544)->MakeInvincible();
	CreateObjectAbove(WindGenerator, 400, 544)->MakeInvincible();
	return;
}

private func InitMiddleIsland()
{
	// A catapult to get to the bottom island.
	var catapult = CreateObjectAbove(Catapult, 760, 408);
	catapult->MakeInvincible();
	catapult->TurnLeft();
	
	var chemical_lab = CreateObjectAbove(ChemicalLab, 850, 368);
	chemical_lab->MakeInvincible();
	chemical_lab->CreateContents(Dynamite, 5);
	
	CreateObjectAbove(WindGenerator, 890, 368)->MakeInvincible();	
	
	var sawmill = CreateObjectAbove(Sawmill, 996, 360);
	sawmill->MakeInvincible();
	sawmill->SetDir(DIR_Right);
	
	// A chest with a windbag on the small island (this is the easter egg).
	var chest = CreateObjectAbove(Chest, 1004, 176);
	chest->MakeInvincible();
	chest->CreateContents(WindBag);
	return;
}

private func InitTopIsland()
{
	// A catapult to get to the middle island.
	var catapult = CreateObjectAbove(Catapult, 432, 248);
	catapult->MakeInvincible();
	
	var elevator = CreateObjectAbove(Elevator, 312, 240);
	elevator->SetDir(DIR_Right);
	elevator->MakeInvincible();
	elevator->CreateShaft(200);
	var case = elevator->GetCase();
	case->SetPosition(case->GetX(), 496);
	case->MakeInvincible();
	
	var workshop = CreateObjectAbove(ToolsWorkshop, 220, 240);
	workshop->MakeInvincible();
	workshop->CreateContents(Hammer, 2);
	workshop->CreateContents(Shovel, 2);
	workshop->CreateContents(Pickaxe, 2);
	
	CreateObjectAbove(Flagpole, 356, 240)->MakeInvincible();
	CreateObjectAbove(WindGenerator, 270, 240)->MakeInvincible();	
	return;
}

private func InitVegetation()
{
	Grass->Place(85);
	PlaceObjects(Rock, 20, "Earth");
	PlaceObjects(Firestone, 8, "Earth");
	Branch->Place(10);
	Mushroom->Place(12);
	Flower->Place(10);
	Trunk->Place(3);
	Tree_Deciduous->Place(12);
	Tree_Coniferous2->Place(2);
	Tree_Coniferous3->Place(2);
	return;
}

private func InitAnimals()
{
	// Some animals as atmosphere.
	Butterfly->Place(20);
	Zaphive->Place(2);
	Mosquito->Place(2);
	return;
}

// Initializes the AI: which is all defined in System.ocg
private func InitAI()
{
	// Village head.
	var npc_head = CreateObjectAbove(Clonk, 250, 558);
	npc_head->SetName("Archibald");
	npc_head->SetObjectLayer(npc_head);
	npc_head->SetDir(DIR_Left);
	npc_head->SetDialogue("VillageHead");
	npc_head->SetAlternativeSkin("Sage");
	
	// Skyville head.
	var npc_head = CreateObjectAbove(Clonk, 260, 558);
	npc_head->SetName("Ludwig");
	npc_head->SetObjectLayer(npc_head);
	npc_head->SetDir(DIR_Left);
	npc_head->SetDialogue("SkyvilleHead");
	npc_head->SetAlternativeSkin("MaleBlackHair");
	return;
}

/*-- Player Handling --*/

protected func InitializePlayer(int plr)
{
	// Position player's clonk.
	var clonk = GetCrew(plr);
	clonk->SetPosition(220, 558);
	clonk->CreateContents(Shovel);
	var effect = AddEffect("ClonkRestore", clonk, 100, 10);
	effect.to_x = 220;
	effect.to_y = 558;

	// Standard player zoom for tutorials.
	SetPlayerViewLock(plr, true);
	SetPlayerZoomByViewRange(plr, 300, nil, PLRZOOM_Direct | PLRZOOM_Set | PLRZOOM_LimitMax);
	SetPlayerZoomByViewRange(plr, LandscapeWidth(), nil, PLRZOOM_LimitMax);
	
	// Claim ownership of structures.
	for (var structure in FindObjects(Find_Or(Find_Category(C4D_Structure), Find_Func("IsFlagpole"))))
		structure->SetOwner(plr);
		
	// Knowledge and base material for this round.
	SetPlrKnowledge(plr, Compensator);
	SetPlrKnowledge(plr, SteamEngine);
	SetPlrKnowledge(plr, Airplane);
	SetBaseMaterial(plr, Metal, 20);
	
	// Set wealth to buy items.
	SetWealth(plr, 400);
	
	// Add an effect to the clonk to track the goal.
	var track_goal = AddEffect("TrackGoal", nil, 100, 2);
	track_goal.plr = plr;
	
	// Start the intro sequence.
	StartSequence("Intro", 0, plr);
	
	// Create tutorial guide and control effect.
	guide = CreateObject(TutorialGuide, 0, 0, plr);
	guide->HideGuide();
	var effect = AddEffect("TutorialReachedSkyIsland", nil, 100, 5);
	effect.plr = plr;
	return;
}


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

global func FxTrackGoalTimer(object target, proplist effect, int time)
{
	if (FindObject(Find_ID(Airplane)))
	{
		StartSequence("Outro", 0, effect.plr);
		return FX_Execute_Kill;
	}
	return FX_OK;
}

public func ShowLastGuideMessage()
{
	guide->AddGuideMessage("$MsgTutorialCompleted$");
	guide->ShowGuideMessage();
	guide->ShowGuide();
	return;
}


/*-- Guide Messages --*/

public func OnIntroSequenceFinished()
{
	var interact = GetPlayerControlAssignment(guide->GetOwner(), CON_Interact, true, true);
	guide->AddGuideMessage(Format("$MsgTutorialTakeElevator$", interact));
	guide->ShowGuide();
	guide->ShowGuideMessage();
	return;
}

global func FxTutorialReachedSkyIslandTimer(object target, proplist effect)
{
	var crew = GetCrew(effect.plr);
	if (crew && FindObject(Find_ID(Hammer), Find_Container(crew)))
	{
		guide->AddGuideMessage("$MsgTutorialBuildCompensator$");
		guide->ShowGuideMessage();
		var new_effect = AddEffect("TutorialPlacedCompensatorSite", nil, 100, 5);
		new_effect.plr = effect.plr;
		return FX_Execute_Kill;
	}
	return FX_OK;
}

global func FxTutorialPlacedCompensatorSiteTimer(object target, proplist effect)
{
	var site = FindObject(Find_ID(ConstructionSite), Find_AtRect(160, 260, 80, 40));
	var compensator = FindObject(Find_ID(Compensator), Find_AtRect(160, 260, 80, 40));
	if ((site && site.definition == Compensator) || compensator)
	{
		var interaction_menu = GetPlayerControlAssignment(effect.plr, CON_Contents, true, true);
		guide->AddGuideMessage(Format("$MsgTutorialBuyMetal$", interaction_menu));
		guide->ShowGuideMessage();
		var new_effect = AddEffect("TutorialFinishedCompensator", nil, 100, 5);
		new_effect.plr = effect.plr;
		return FX_Execute_Kill;
	}
	return FX_OK;
}

global func FxTutorialFinishedCompensatorTimer(object target, proplist effect)
{
	if (FindObject(Find_ID(Compensator), Find_AtRect(160, 260, 80, 40)))
	{
		guide->AddGuideMessage("$MsgTutorialPowerOverview$");
		guide->ShowGuideMessage();
		var new_effect = AddEffect("TutorialLookedAtPowerOverview", nil, 100, 5);
		new_effect.plr = effect.plr;
		return FX_Execute_Kill;
	}
	return FX_OK;
}

global func FxTutorialLookedAtPowerOverviewTimer(object target, proplist effect)
{
	// TODO: fix me (should be triggered when the E menu is openend).
	if (effect.looked_at || true)
	{
		var interact = GetPlayerControlAssignment(effect.plr, CON_Interact, true, true);
		var interact_cycle = GetPlayerControlAssignment(effect.plr, CON_InteractNext_CycleObject, true, true);
		guide->AddGuideMessage(Format("$MsgTutorialEnterCatapult$", interact, interact_cycle, interact));
		guide->ShowGuideMessage();
		var new_effect = AddEffect("TutorialEnteredCatapult", nil, 100, 5);
		new_effect.plr = effect.plr;
		return FX_Execute_Kill;
	}
	return FX_OK;
}

global func FxTutorialEnteredCatapultTimer(object target, proplist effect)
{
	var catapult = FindObject(Find_ID(Catapult), Find_Distance(80, 432, 248));
	if (catapult && GetCrew(effect.plr) == FindObject(Find_OCF(OCF_CrewMember), Find_Container(catapult)))
	{
		var zoom_in = GetPlayerControlAssignment(effect.plr, CON_WheelZoomIn, true, true);
		var zoom_out = GetPlayerControlAssignment(effect.plr, CON_WheelZoomOut, true, true);
		var use = GetPlayerControlAssignment(effect.plr, CON_Use, true, true);
		guide->AddGuideMessage(Format("$MsgTutorialLaunchCatapult$", zoom_in, zoom_out, use));
		guide->ShowGuideMessage();
		var new_effect = AddEffect("TutorialReachedMiddleIsland", nil, 100, 5);
		new_effect.plr = effect.plr;
		return FX_Execute_Kill;
	}
	return FX_OK;
}

global func FxTutorialReachedMiddleIslandTimer(object target, proplist effect)
{
	if (FindObject(Find_OCF(OCF_CrewMember), Find_Owner(effect.plr), Find_InRect(744, 336, 300, 280)))
	{
		guide->AddGuideMessage("$MsgTutorialBuildSteamEngine$");
		guide->ShowGuideMessage();
		var new_effect = AddEffect("TutorialPlacedSteamEngineSite", nil, 100, 5);
		new_effect.plr = effect.plr;
		return FX_Execute_Kill;
	}
	return FX_OK;
}

global func FxTutorialPlacedSteamEngineSiteTimer(object target, proplist effect)
{
	var site = FindObject(Find_ID(ConstructionSite), Find_AtRect(832, 400, 72, 56));
	if (site && site.definition == SteamEngine)
	{
		guide->AddGuideMessage("$MsgTutorialTransportMaterials$");
		guide->ShowGuideMessage();
		var new_effect = AddEffect("TutorialReachedTopIsland", nil, 100, 5);
		new_effect.plr = effect.plr;
		return FX_Execute_Kill;
	}
	return FX_OK;
}

global func FxTutorialReachedTopIslandTimer(object target, proplist effect)
{
	if (FindObject(Find_OCF(OCF_CrewMember), Find_Owner(effect.plr), Find_InRect(200, 200, 200, 40)))
	{
		var interact = GetPlayerControlAssignment(effect.plr, CON_Interact, true, true);
		guide->AddGuideMessage(Format("$MsgTutorialShootCoalAndMetal$", interact));
		guide->ShowGuideMessage();
		var new_effect = AddEffect("TutorialReachedMiddleIslandSecond", nil, 100, 5);
		new_effect.plr = effect.plr;
		return FX_Execute_Kill;
	}
	return FX_OK;
}

global func FxTutorialReachedMiddleIslandSecondTimer(object target, proplist effect)
{
	if (FindObject(Find_OCF(OCF_CrewMember), Find_Owner(effect.plr), Find_InRect(744, 336, 300, 280)))
	{
		guide->AddGuideMessage("$MsgTutorialFinishSteamEngine$");
		guide->ShowGuideMessage();
		return FX_Execute_Kill;
	}
	return FX_OK;
}

protected func OnGuideMessageShown(int plr, int index)
{
	// Show the location for the compensator.
	if (index == 1)
	{
		TutArrowShowPos(200, 300, 135);
	}
	
	// Show the location for the steam engine.
	if (index == 6)
	{
		TutArrowShowPos(872, 456, 135);
	}
	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;
		// 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);
		restorer->SetRestoreObject(clonk, nil, to_x, to_y, 0, "ClonkRestore");
		GameCall("OnClonkRestore", clonk);
	}
	return FX_OK;
}
