forked from Mirrors/openclonk
400 lines
9.6 KiB
C
400 lines
9.6 KiB
C
/**
|
|
Sawmill
|
|
Cuts trees or other objects into wood. Accepts only objects purely made from wood (like trees).
|
|
|
|
@authors Ringwaul, Clonkonaut
|
|
*/
|
|
|
|
#include Library_Structure
|
|
#include Library_Ownable
|
|
#include Library_PowerConsumer
|
|
|
|
local running = false;
|
|
local power = false;
|
|
|
|
public func Construction()
|
|
{
|
|
SetProperty("MeshTransformation", Trans_Rotate(-20, 0, 1, 0));
|
|
SetAction("Default");
|
|
return _inherited(...);
|
|
}
|
|
|
|
public func IsHammerBuildable() { return true; }
|
|
|
|
public func Initialize()
|
|
{
|
|
this.SpinAnimation = PlayAnimation("work", 10, Anim_Const(0));
|
|
AddTimer("CollectTrees", 4);
|
|
return _inherited(...);
|
|
}
|
|
|
|
/*-- Interaction --*/
|
|
|
|
// Sawmill acts as a container to be able to collect wooden objects.
|
|
public func IsContainer() { return true; }
|
|
|
|
// Do not show normal inventory menu. Instead we show the remaining wood in an extra menu.
|
|
public func RejectContentsMenu() { return true; }
|
|
|
|
// Sawmill can't be interacted with.
|
|
public func IsInteractable() { return false; }
|
|
|
|
/*-- Production --*/
|
|
|
|
private func Collection(object obj)
|
|
{
|
|
Sound("Objects::Clonk");
|
|
Saw(obj);
|
|
}
|
|
|
|
private func RejectCollect(id id_def, object collect)
|
|
{
|
|
// Don't collect wood
|
|
if (id_def == Wood)
|
|
return true;
|
|
if (CheckWoodObject(collect))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
// Timer, check for objects to collect in the designated collection zone
|
|
public func CollectTrees()
|
|
{
|
|
if (GetCon() < 100)
|
|
return;
|
|
var tree = FindObject(Find_AtPoint(), Find_Func("IsTree"), Find_Not(Find_Func("IsStanding")), Find_Func("GetComponent", Wood));
|
|
// If there is no tree in front of the sawmill try to get one from the cable car network.
|
|
if (!tree)
|
|
RequestTree();
|
|
// Only take one tree at a time.
|
|
if (!ContentsCount(Wood) && tree)
|
|
Saw(tree);
|
|
return;
|
|
}
|
|
|
|
// Returns whether the object is made purely out of wood.
|
|
private func CheckWoodObject(object target)
|
|
{
|
|
if (target->GetComponent(nil, 0) != Wood)
|
|
return false;
|
|
if (target->GetComponent(nil, 1))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
// Provides an own interaction menu.
|
|
public func HasInteractionMenu() { return true; }
|
|
|
|
// Show a helpful hint to the player. The hint is colored and titled the same as the production menu for more visual coherence.
|
|
public func GetInteractionMenus(object clonk)
|
|
{
|
|
var menus = _inherited(clonk, ...) ?? [];
|
|
var prod_menu =
|
|
{
|
|
title = "$Production$",
|
|
entries_callback = this.GetInfoMenuEntries,
|
|
callback = nil,
|
|
BackgroundColor = RGB(0, 0, 50),
|
|
Priority = 20
|
|
};
|
|
PushBack(menus, prod_menu);
|
|
|
|
return menus;
|
|
}
|
|
|
|
public func GetInfoMenuEntries()
|
|
{
|
|
var wood_count = ContentsCount(Wood);
|
|
var info_text =
|
|
{
|
|
Right = "100%", Bottom = "6em",
|
|
text = {Left = "2em", Text = "$AutoProduction$", Style = GUI_TextVCenter | GUI_TextHCenter},
|
|
image = {Right = "2em", Bottom = "2em", Symbol = Wood},
|
|
queue =
|
|
{
|
|
Top = "100% - 1.5em",
|
|
Style = GUI_TextRight,
|
|
Text = Format("$WoodInQueue$: %2d {{Wood}}", wood_count)
|
|
}
|
|
};
|
|
return [{symbol = Wood, custom = info_text}];
|
|
}
|
|
|
|
public func Saw(object target)
|
|
{
|
|
if (target->Contained() != this)
|
|
target->Enter(this);
|
|
target->Split2Components();
|
|
AddEffect("WoodProduction", this, 100, 3, this);
|
|
// Refresh interaction menus to show the wood count.
|
|
UpdateInteractionMenus(this.GetInfoMenuEntries);
|
|
return true;
|
|
}
|
|
|
|
private func ProductionTime(id product) { return _inherited(product, ...) ?? 100; }
|
|
private func PowerNeed() { return 20; }
|
|
|
|
private func FxWoodProductionStart(object t, proplist effect, int temp)
|
|
{
|
|
if (temp) return;
|
|
|
|
effect.runtime = 0;
|
|
effect.starttime = 0;
|
|
|
|
RegisterPowerRequest(PowerNeed());
|
|
}
|
|
|
|
private func FxWoodProductionTimer(object t, proplist effect, int time)
|
|
{
|
|
if (!power)
|
|
{
|
|
if (effect.starttime)
|
|
effect.starttime = 0;
|
|
return FX_OK;
|
|
}
|
|
|
|
if (!(time%20))
|
|
Smoke(10 * GetCalcDir(),10,10);
|
|
|
|
if (!running)
|
|
{
|
|
SpinOn(effect.starttime);
|
|
effect.starttime += 3;
|
|
return FX_OK;
|
|
}
|
|
|
|
effect.runtime += 3;
|
|
var dir = GetCalcDir();
|
|
CreateParticle("WoodChip", PV_Random(-7 * dir, -3 * dir), PV_Random(3, 6), PV_Random(-5 * dir, -11 * dir), PV_Random(-4, -2), PV_Random(36 * 3, 36 * 10), Particles_WoodChip(), 3);
|
|
|
|
if (effect.runtime >= ProductionTime())
|
|
{
|
|
EjectWood();
|
|
effect.runtime = 0;
|
|
}
|
|
else
|
|
return FX_OK;
|
|
|
|
if (!ContentsCount(Wood))
|
|
return FX_Execute_Kill;
|
|
}
|
|
|
|
private func FxWoodProductionStop(object t, proplist effect, int r, bool temp)
|
|
{
|
|
if (temp) return;
|
|
|
|
UnregisterPowerRequest();
|
|
SpinOff();
|
|
power = false;
|
|
}
|
|
|
|
public func OnEnoughPower()
|
|
{
|
|
if (power) return _inherited(...);
|
|
|
|
power = true;
|
|
return _inherited(...);
|
|
}
|
|
|
|
public func OnNotEnoughPower()
|
|
{
|
|
if (!power) return _inherited(...);
|
|
|
|
power = false;
|
|
SpinOff();
|
|
return _inherited(...);
|
|
}
|
|
|
|
public func EjectWood()
|
|
{
|
|
var wood = FindContents(Wood);
|
|
if (!wood) return;
|
|
|
|
wood->Exit(-25 * GetCalcDir(), -8, 30 - Random(59), -2 * GetCalcDir(), 1);
|
|
Sound("Structures::EjectionPop");
|
|
|
|
// Refresh interaction menus to show the wood count.
|
|
UpdateInteractionMenus(this.GetInfoMenuEntries);
|
|
}
|
|
|
|
/*-- Animation --*/
|
|
|
|
private func SpinOn(int diff)
|
|
{
|
|
var spin;
|
|
var rotate = 0;
|
|
if (diff == 0)
|
|
{
|
|
ClearScheduleCall(this, "SpinOff");
|
|
Sound("Sawmill::EngineStart");
|
|
SetMeshMaterial("Beltspin", 1);
|
|
}
|
|
if (diff > 20) rotate = Sin(70 * diff, 1) - 1;
|
|
if (Inside(diff, 0, 20)) spin = 100;
|
|
if (Inside(diff, 21, 40)) spin = 75;
|
|
if (Inside(diff, 41, 60)) spin = 50;
|
|
if (Inside(diff, 61, 80)) spin = 30;
|
|
if (diff > 80)
|
|
{
|
|
spin = 30;
|
|
rotate = 0;
|
|
SetMeshMaterial("SawmillBlade.Spin", 2);
|
|
running = true;
|
|
Sound("Structures::SawmillRipcut", {loop_count = +1});
|
|
Sound("Sawmill::EngineLoop", {loop_count = +1});
|
|
}
|
|
|
|
SetProperty("MeshTransformation", Trans_Mul(Trans_Rotate(-20, 0, 1, 0), Trans_Rotate(rotate, 1, 0, 0)));
|
|
SetAnimationPosition(this.SpinAnimation, Anim_Linear(GetAnimationPosition(this.SpinAnimation), 0, GetAnimationLength("work"), spin, ANIM_Loop));
|
|
}
|
|
|
|
private func SpinOff(int call)
|
|
{
|
|
var spin;
|
|
if (!call)
|
|
{
|
|
running = false;
|
|
spin = 50;
|
|
SetMeshMaterial("SawmillBlade", 2);
|
|
Sound("Structures::SawmillRipcut", {loop_count = -1});
|
|
SetProperty("MeshTransformation", Trans_Rotate(-20, 0, 1, 0));
|
|
}
|
|
if (call == 1) spin = 75;
|
|
if (call == 2)
|
|
{
|
|
spin = 100;
|
|
Sound("Sawmill::EngineLoop", {loop_count = -1});
|
|
Sound("Sawmill::EngineStop");
|
|
}
|
|
if (call == 3) spin = 150;
|
|
if (call == 4)
|
|
{
|
|
SetMeshMaterial("SawmillBelt", 1);
|
|
SetAnimationPosition(this.SpinAnimation, Anim_Const(GetAnimationPosition(this.SpinAnimation)));
|
|
return;
|
|
}
|
|
|
|
SetAnimationPosition(this.SpinAnimation, Anim_Linear(GetAnimationPosition(this.SpinAnimation), 0, GetAnimationLength("work"), spin, ANIM_Loop));
|
|
|
|
ScheduleCall(this, "SpinOff", this.SpinStep * 2, nil, call+1);
|
|
}
|
|
|
|
|
|
/*-- Cable Network --*/
|
|
|
|
local cable_station;
|
|
|
|
public func AcceptsCableStationConnection() { return true; }
|
|
|
|
public func IsNoCableStationConnected() { return !cable_station; }
|
|
|
|
public func ConnectCableStation(object station)
|
|
{
|
|
cable_station = station;
|
|
}
|
|
|
|
private func RequestTree()
|
|
{
|
|
if (!cable_station)
|
|
return;
|
|
// Find a collectible tree on the network.
|
|
var collectible_tree = cable_station->FindObjectOnNetworkCables(Find_And(Find_Func("IsTree"), Find_Not(Find_Property("is_being_cable_car_collected"))));
|
|
if (!collectible_tree)
|
|
return;
|
|
// Find an available hoist in the network.
|
|
var hoist = cable_station->FindCableCar(Find_And(Find_Not(Find_Func("GetAttachedVehicle")), Find_Not(Find_Property("is_busy_collecting_tree"))));
|
|
if (!hoist)
|
|
return;
|
|
hoist->CreateEffect(Sawmill.FxCableCarCollectTree, 100, 1, collectible_tree, cable_station);
|
|
return;
|
|
}
|
|
|
|
local FxCableCarCollectTree = new Effect
|
|
{
|
|
Construction = func(array collectible_tree, object sawmill_station)
|
|
{
|
|
this.tree = collectible_tree[0];
|
|
this.station_1 = collectible_tree[1];
|
|
this.station_2 = collectible_tree[2];
|
|
this.station_sawmill = sawmill_station;
|
|
this.tree.is_being_cable_car_collected = true;
|
|
Target.is_busy_collecting_tree = true;
|
|
Target->SetDestination(this.station_1);
|
|
return FX_OK;
|
|
},
|
|
Timer = func()
|
|
{
|
|
if (!this.station_1 || !this.station_2 || !this.station_sawmill)
|
|
return FX_Execute_Kill;
|
|
if (IsValueInArray(this.station_1->GetIdleCars(), Target))
|
|
Target->SetDestination(this.station_2);
|
|
if (IsValueInArray(this.station_2->GetIdleCars(), Target))
|
|
Target->SetDestination(this.station_sawmill);
|
|
var tree = Target->FindObject(Target->Find_AtPoint(), Find_InArray([this.tree]));
|
|
if (tree && !tree.has_been_picked_up)
|
|
{
|
|
this.tree.has_been_picked_up = true;
|
|
this.tree->CreateEffect(Sawmill.FxCableCarRotateTree, 100, 1);
|
|
Target->PickupVehicle(this.tree);
|
|
}
|
|
if (IsValueInArray(this.station_sawmill->GetIdleCars(), Target))
|
|
return FX_Execute_Kill;
|
|
return FX_OK;
|
|
},
|
|
Destruction = func()
|
|
{
|
|
//this.tree.is_being_cable_car_collected = false;
|
|
Target.is_busy_collecting_tree = false;
|
|
Target->DropVehicle();
|
|
}
|
|
};
|
|
|
|
local FxCableCarRotateTree = new Effect
|
|
{
|
|
Construction = func(int rotate_goal)
|
|
{
|
|
this.rotate_goal = 90;
|
|
if (Target->GetR() < 0)
|
|
this.rotate_goal = -90;
|
|
},
|
|
Timer = func()
|
|
{
|
|
var step = 3;
|
|
var dr = this.rotate_goal - Target->GetR();
|
|
if (Inside(dr, -step, step))
|
|
return FX_Execute_Kill;
|
|
Target->SetR(Target->GetR() + BoundBy(dr, -step, step));
|
|
return FX_OK;
|
|
}
|
|
};
|
|
|
|
|
|
/*-- Properties --*/
|
|
|
|
local ActMap = {
|
|
Default = {
|
|
Prototype = Action,
|
|
Name = "Default",
|
|
Procedure = DFA_NONE,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 1,
|
|
Delay = 0,
|
|
FacetBase = 1,
|
|
NextAction = "Default",
|
|
},
|
|
};
|
|
|
|
func Definition(def)
|
|
{
|
|
SetProperty("PictureTransformation", Trans_Mul(Trans_Translate(2000, 0, 7000), Trans_Rotate(-20, 1, 0, 0),Trans_Rotate(30, 0, 1, 0)), def);
|
|
return _inherited(def, ...);
|
|
}
|
|
local Name = "$Name$";
|
|
local Description = "$Description$";
|
|
local SpinStep = 30;
|
|
local ContainBlast = true;
|
|
local BlastIncinerate = 100;
|
|
local FireproofContainer = true;
|
|
local HitPoints = 70;
|
|
local Components = {Rock = 4, Wood = 1}; |