openclonk/planet/Tutorials.ocf/Tutorial07.ocs/Script.c

379 lines
10 KiB
C

/**
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.
SetNextScenario("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.
SetNextScenario("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;
}