forked from Mirrors/openclonk
201 lines
4.7 KiB
C
201 lines
4.7 KiB
C
/*--
|
|
Stackable
|
|
Author: Newton
|
|
|
|
Including this object means, the object is stackable. Other objects of
|
|
the same type will be added automatically to the object. This functionality
|
|
is similar to the Pack-functionality of the arrows in old clonk titles only
|
|
more general.
|
|
The count of how many objects are stacked together (into a single one, this
|
|
one) is shown in the picture of the object and can be queried and set via
|
|
GetStackCount()/SetStackCount().
|
|
To take one object of the stack, call TakeObject(). As long
|
|
as the object exists, one can always take an object, even if it is the last
|
|
one (self). This object is always outside.
|
|
|
|
On entrance (or to be more precise: on RejectEntrance), it will be checked
|
|
if the entering stackable object can be distributed over the other objects
|
|
of the same ID. If yes, this object is deleted and the other object(s) will
|
|
have a higher stack-count.
|
|
|
|
Example 1:
|
|
'15x Arrow' is about to enter a clonk which has '5x Arrow'. 15 will be added
|
|
to the stack-count of the clonks '5x Arrow'-object (making it '20x Arrow'),
|
|
the entering object will be deleted.
|
|
|
|
Example 2:
|
|
'17x Arrow' is about to enter a clonk which has '15x Arrow' and a bow with
|
|
'10x Arrow' in it's ammunition slot. 10 will be added to the stack-count
|
|
of the arrows in the bow, 5 to the stack-count of the arrows in the clonk
|
|
(assuming MaxStackCount() is 20) and the original arrows-object will have
|
|
2 arrows left. If there is an inventory slot left, the '2x Arrow" object
|
|
will enter the clonk.
|
|
|
|
Most objects which can be stacked might want to set different pictures
|
|
and ingame graphics for different counts of objects. This can be done
|
|
by overloading UpdatePicture(), but remember to write _inherited() then.
|
|
--*/
|
|
|
|
|
|
local count;
|
|
|
|
public func IsStackable() { return true; }
|
|
public func GetStackCount() { return Max(1, count); }
|
|
public func MaxStackCount() { return 20; }
|
|
|
|
protected func Construction()
|
|
{
|
|
count = MaxStackCount();
|
|
}
|
|
|
|
public func Stack(object obj)
|
|
{
|
|
if (obj->GetID() != GetID())
|
|
return 0;
|
|
|
|
var howmany = Min(obj->GetStackCount(), MaxStackCount() - GetStackCount());
|
|
|
|
if (count + howmany > 999)
|
|
return 0;
|
|
|
|
SetStackCount(count + howmany);
|
|
|
|
return howmany;
|
|
}
|
|
|
|
public func SetStackCount(int amount)
|
|
{
|
|
count = BoundBy(amount, 0, 999);
|
|
Update();
|
|
}
|
|
|
|
public func TakeObject()
|
|
{
|
|
if (count == 1)
|
|
{
|
|
Exit();
|
|
return this;
|
|
}
|
|
else if (count > 1)
|
|
{
|
|
SetStackCount(count - 1);
|
|
var take = CreateObject(GetID(), 0, 0, GetOwner());
|
|
take->SetStackCount(1);
|
|
Update();
|
|
return take;
|
|
}
|
|
}
|
|
|
|
public func Update()
|
|
{
|
|
UpdatePicture();
|
|
UpdateMass();
|
|
UpdateName();
|
|
// notify hud
|
|
var container = Contained();
|
|
if (container)
|
|
{
|
|
// has an extra slot
|
|
if (container->~HasExtraSlot())
|
|
container->~NotifyHUD();
|
|
// is a clonk with new inventory system
|
|
else if (container->~GetSelected())
|
|
{
|
|
var pos = container->GetItemPos(this);
|
|
container->~OnSlotFull(pos);
|
|
}
|
|
}
|
|
}
|
|
|
|
private func UpdatePicture()
|
|
{
|
|
var one = GetStackCount() % 10;
|
|
var ten = (GetStackCount() / 10) % 10;
|
|
var hun = (GetStackCount() / 100) % 10;
|
|
|
|
var s = 400;
|
|
var yoffs = 14000;
|
|
var xoffs = 22000;
|
|
var spacing = 14000;
|
|
|
|
if (hun > 0)
|
|
{
|
|
SetGraphics(Format("%d", hun), Icon_Number, 10, GFXOV_MODE_Picture);
|
|
SetObjDrawTransform(s, 0, xoffs - 2 * spacing, 0, s, yoffs, 10);
|
|
}
|
|
else
|
|
SetGraphics(nil, nil, 10);
|
|
|
|
if (ten > 0 || hun > 0)
|
|
{
|
|
SetGraphics(Format("%d", ten), Icon_Number, 11, GFXOV_MODE_Picture);
|
|
SetObjDrawTransform(s, 0, xoffs - spacing, 0, s, yoffs, 11);
|
|
}
|
|
else
|
|
SetGraphics(nil, nil, 11);
|
|
|
|
SetGraphics(Format("%d", one), Icon_Number, 12, GFXOV_MODE_Picture);
|
|
SetObjDrawTransform(s, 0, xoffs, 0, s, yoffs, 12);
|
|
}
|
|
|
|
private func UpdateName()
|
|
{
|
|
SetName(Format("%dx %s", GetStackCount(), GetID()->GetName()));
|
|
}
|
|
|
|
private func UpdateMass()
|
|
{
|
|
SetMass(GetID()->GetMass() * Max(GetStackCount(), 1) / MaxStackCount());
|
|
}
|
|
|
|
protected func RejectEntrance(object into)
|
|
{
|
|
if (TryPutInto(into))
|
|
return true;
|
|
return _inherited(into, ...);
|
|
}
|
|
|
|
/* Value */
|
|
|
|
public func CalcValue(object in_base, int for_plr)
|
|
{
|
|
return GetID()->GetValue() * Max(GetStackCount(), 1) / MaxStackCount();
|
|
}
|
|
|
|
private func TryPutInto(object into)
|
|
{
|
|
var contents = FindObjects(Find_Container(into));
|
|
|
|
// first check if stackable can be put into object with extra slot
|
|
for (var content in contents)
|
|
{
|
|
if (!content)
|
|
continue;
|
|
if (content->~HasExtraSlot())
|
|
if (TryPutInto(content))
|
|
return true;
|
|
}
|
|
|
|
// then check this object
|
|
for (var content in contents)
|
|
{
|
|
var howmany = 0;
|
|
if (!content)
|
|
continue;
|
|
if (content->~IsStackable())
|
|
if (content->GetID() == GetID())
|
|
if (howmany = content->Stack(this))
|
|
{
|
|
count -= howmany;
|
|
if(count <= 0)
|
|
{
|
|
RemoveObject();
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
Update();
|
|
return false;
|
|
}
|