forked from Mirrors/openclonk
312 lines
6.1 KiB
C
312 lines
6.1 KiB
C
/**
|
|
Dynamite box
|
|
Contains five dynamite sticks which can be placed and detonated from a distance.
|
|
|
|
@author: Newton
|
|
*/
|
|
|
|
#include Library_HasExtraSlot
|
|
|
|
static const DYNA_MaxLength = 500;
|
|
static const DYNA_MaxCount = 5;
|
|
|
|
local count;
|
|
local dynamite_sticks;
|
|
local wires;
|
|
local wire;
|
|
|
|
/*-- Engine Callbacks --*/
|
|
|
|
func Initialize()
|
|
{
|
|
CreateContents(Dynamite, DYNA_MaxCount);
|
|
|
|
count = DYNA_MaxCount;
|
|
dynamite_sticks = [];
|
|
wires = [];
|
|
for (var i = 0; i < count; i++)
|
|
{
|
|
dynamite_sticks[i] = nil;
|
|
wires[i] = nil;
|
|
}
|
|
|
|
// Hide it TODO: Remove if the mesh isn't shown if there is a picture set
|
|
this.PictureTransformation = Trans_Scale();
|
|
UpdatePicture();
|
|
}
|
|
|
|
func Hit()
|
|
{
|
|
Sound("Hits::Materials::Wood::DullWoodHit?");
|
|
}
|
|
|
|
func Incineration(int caused_by)
|
|
{
|
|
ActivateFuse();
|
|
if (!GetEffect("Fuse", this)) AddEffect("Fuse", this, 100, 1, this);
|
|
Sound("Fire::Fuse");
|
|
SetController(caused_by);
|
|
}
|
|
|
|
func Damage(int change, int type, int by_player)
|
|
{
|
|
Incinerate(nil, by_player);
|
|
}
|
|
|
|
func RejectCollect(id def, object obj)
|
|
{
|
|
if (obj->GetID() != Dynamite)
|
|
return true;
|
|
// One dynamite box can only support 5 sticks of dynamite, regardless if these are in the box
|
|
// or already taken out (connected with wires)
|
|
var sticks = ContentsCount(Dynamite);
|
|
for (var i = 0; i < GetLength(wires); i++)
|
|
if (wires[i])
|
|
sticks++;
|
|
|
|
if (sticks >= DYNA_MaxCount)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
func Ejection()
|
|
{
|
|
count--;
|
|
|
|
if (count == 0)
|
|
{
|
|
ChangeToIgniter();
|
|
if (Contained())
|
|
{
|
|
var pos = Contained()->~GetItemPos(this);
|
|
Contained()->~UpdateAttach();
|
|
Contained()->~OnSlotFull(pos);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
UpdatePicture();
|
|
}
|
|
|
|
// Make sure the inventory gets notified of the changes.
|
|
if (Contained())
|
|
Contained()->~OnInventoryChange();
|
|
}
|
|
|
|
func ContentsDestruction()
|
|
{
|
|
Ejection();
|
|
}
|
|
|
|
func Collection2()
|
|
{
|
|
if (count == 0 && GetID() == Igniter)
|
|
{
|
|
ChangeToBox();
|
|
if (Contained())
|
|
{
|
|
var pos = Contained()->~GetItemPos(this);
|
|
Contained()->~UpdateAttach();
|
|
Contained()->~OnSlotFull(pos);
|
|
}
|
|
}
|
|
|
|
count++;
|
|
|
|
UpdatePicture();
|
|
|
|
if (Contained())
|
|
Contained()->~OnInventoryChange();
|
|
}
|
|
|
|
/*-- Callbacks --*/
|
|
|
|
// Do not stack empty dynamite boxes with full ones.
|
|
public func CanBeStackedWith(object other)
|
|
{
|
|
if (this.count != other.count) return false;
|
|
return inherited(other, ...);
|
|
}
|
|
|
|
// Drop connected or fusing boxes
|
|
public func IsDroppedOnDeath(object clonk)
|
|
{
|
|
return GetEffect("Fuse", this) || wire;
|
|
}
|
|
|
|
public func OnFuseFinished(object fuse)
|
|
{
|
|
SetController(fuse->GetController());
|
|
DoExplode();
|
|
}
|
|
|
|
public func OnCannonShot(object cannon)
|
|
{
|
|
Incinerate(nil, cannon->GetController());
|
|
}
|
|
|
|
/*-- Usage --*/
|
|
|
|
public func SetDynamiteCount(int new_count)
|
|
{
|
|
count = BoundBy(new_count, 1, DYNA_MaxCount);
|
|
UpdatePicture();
|
|
// Update inventory if contained in a crew member.
|
|
if (Contained())
|
|
Contained()->~OnInventoryChange();
|
|
}
|
|
|
|
public func ControlUse(object clonk, int x, int y)
|
|
{
|
|
var dynamite = Contents();
|
|
|
|
if (!dynamite || dynamite->GetID() != Dynamite)
|
|
return false;
|
|
|
|
if (!dynamite->ControlUse(clonk, x, y, 1))
|
|
return true;
|
|
|
|
if(wire)
|
|
wire->Connect(dynamite_sticks[count], dynamite);
|
|
|
|
wire = CreateObject(Fuse);
|
|
wire->Connect(dynamite, this);
|
|
Sound("Objects::Connect");
|
|
wires[count] = wire;
|
|
|
|
return true;
|
|
}
|
|
|
|
// Empty this box and turn it into an igniter
|
|
public func ChangeToIgniter()
|
|
{
|
|
if (GetID() == Igniter) return;
|
|
|
|
count = 0;
|
|
UpdatePicture();
|
|
ChangeDef(Igniter);
|
|
SetGraphics("Picture", Igniter, 1, GFXOV_MODE_Picture);
|
|
return true;
|
|
}
|
|
|
|
// Change back into a box
|
|
public func ChangeToBox()
|
|
{
|
|
if (GetID() == DynamiteBox) return;
|
|
|
|
ChangeDef(DynamiteBox);
|
|
UpdatePicture();
|
|
return true;
|
|
}
|
|
|
|
public func ActivateFuse()
|
|
{
|
|
// Activate all fuses.
|
|
for (var obj in FindObjects(Find_Category(C4D_StaticBack), Find_Func("IsFuse"), Find_ActionTargets(this)))
|
|
obj->~StartFusing(this);
|
|
}
|
|
|
|
public func DoExplode()
|
|
{
|
|
// Activate all fuses.
|
|
ActivateFuse();
|
|
// Explode, calc the radius out of the area of a explosion of a single dynamite times the amount of dynamite
|
|
// This results to 18, 25, 31, 36, and 40
|
|
Explode(Sqrt(18**2*count));
|
|
}
|
|
|
|
public func FxFuseTimer(object target, effect, int timer)
|
|
{
|
|
CreateParticle("Fire", 0, 0, PV_Random(-10, 10), PV_Random(-20, 10), PV_Random(10, 40), Particles_Glimmer(), 6);
|
|
if (timer > 90)
|
|
DoExplode();
|
|
return FX_OK;
|
|
}
|
|
|
|
/*-- Production --*/
|
|
|
|
public func IsTool() { return true; }
|
|
public func IsChemicalProduct() { return true; }
|
|
|
|
/*-- Display --*/
|
|
|
|
public func GetCarryMode(object clonk, bool idle)
|
|
{
|
|
if (idle) return CARRY_Back;
|
|
if (clonk->~IsWalking() || clonk->~IsJumping()) return CARRY_BothHands;
|
|
return CARRY_Back;
|
|
}
|
|
|
|
public func GetCarryTransform(object clonk, bool idle, bool nohand, bool second_on_back)
|
|
{
|
|
if (idle)
|
|
{
|
|
if (!second_on_back)
|
|
return Trans_Mul(Trans_Translate(0,3000, 00), Trans_Rotate(-45,0,1));
|
|
else
|
|
return Trans_Mul(Trans_Translate(-5000,3000), Trans_Rotate(-45,0,1));
|
|
}
|
|
if (nohand)
|
|
return Trans_Mul(Trans_Translate(0,-3000, -2200), Trans_Rotate(-45,0,1));
|
|
}
|
|
|
|
public func GetCarryPhase()
|
|
{
|
|
return 450;
|
|
}
|
|
|
|
func UpdatePicture()
|
|
{
|
|
SetGraphics(Format("%d", 6 - count), DynamiteBox, 1, GFXOV_MODE_Picture);
|
|
}
|
|
|
|
// Display the remaining dynamite sticks in menus.
|
|
/*public func GetInventoryIconOverlay()
|
|
{
|
|
// Full boxes don't need an overlay. Same for igniters.
|
|
if (count == DYNA_MaxCount || count <= 0) return nil;
|
|
|
|
// Overlay the sticks.
|
|
var overlay =
|
|
{
|
|
Top = "0.1em",
|
|
Bottom = "1.1em",
|
|
back_stripe =
|
|
{
|
|
Priority = -1,
|
|
Margin = ["0em", "0.3em", "0em", "0.2em"],
|
|
BackgroundColor = RGBa(0, 0, 0, 200)
|
|
}
|
|
};
|
|
|
|
for (var i = 0; i < count; ++i)
|
|
{
|
|
var left = -i * 4 - 10;
|
|
var left_string = ToEmString(left);
|
|
var stick =
|
|
{
|
|
Left = Format("100%% %s", left_string),
|
|
Right = Format("100%% %s + 1em", left_string),
|
|
Symbol = Dynamite
|
|
};
|
|
GuiAddSubwindow(stick, overlay);
|
|
}
|
|
|
|
return overlay;
|
|
}*/
|
|
|
|
func Definition(def)
|
|
{
|
|
SetProperty("PictureTransformation", Trans_Mul(Trans_Rotate(150, 1, 0, 0), Trans_Rotate(140, 0, 1, 0)), def);
|
|
}
|
|
|
|
/*-- Properties --*/
|
|
|
|
local Name = "$Name$";
|
|
local Description = "$Description$";
|
|
local Collectible = true;
|
|
local BlastIncinerate = 1;
|
|
local ContactIncinerate = 2;
|
|
local Components = {Wood = 1, Coal = 2, Firestone = 2};
|
|
local MaxContentsCount = 5; |