/**
	CarryHeavyControl

	Handles the control of carry-heavy-objects as inventory objects.
	Depends on Clonk Control and Inventory
*/

local lib_carryheavy_obj; // object beeing carried with carryheavy

public func GetCarryHeavy() { return lib_carryheavy_obj; }
public func IsCarryingHeavy() { return lib_carryheavy_obj != nil; }


// Helper function to create carry heavy contents without doing the pick up animation.
public func CreateCarryHeavyContents(id obj_id, int amount)
{
	this.BlockCarryHeavyPickUpAnimation = true;
	var res = CreateContents(obj_id, amount);
	this.BlockCarryHeavyPickUpAnimation = false;
	return res;
}

/* Overloads for Inventory */

// Check if we can carry a carry heavy object
protected func RejectCollect(id objid, object obj)
{
	// Carry heavy only gets picked up if none held already
	if(this.inventory.force_collection && obj->~IsCarryHeavy())
	{
		// Collection of that object magically disabled?
		if(GetEffect("NoCollection", obj)) return true;
		
		// Do callbacks to control effects to see if the effect blocks picking up a carry heavy object.
		var block_carry_heavy = false;
		var count = GetEffectCount("*Control*", this), control_effect;
		while (count--)
		{
			control_effect = GetEffect("*Control*", this, count);
			if (control_effect && EffectCall(this, control_effect, "RejectCarryHeavyPickUp", obj))
			{
				block_carry_heavy = true;
				break;
			}
		}

		// Don't pick up if already carrying a heavy object or if it is blocked.
		if (IsCarryingHeavy() || block_carry_heavy)
		{
			CustomMessage("$TxtHandsFull$", this, this->GetController(), 0, 0, 0xff0000);
			return true;
		}
		return false;
	}

	return _inherited(objid,obj,...);
}

// Start visual effect when picking up carry heavy objects
public func Collection2(object obj)
{
	if(obj->~IsCarryHeavy()) // we can assume that we don't have a carryheavy object yet. If we do, Scripters are to blame.
	{
		CarryHeavy(obj);
		DoLiftCarryHeavy(obj);
		return true;
	}
	return _inherited(obj,...);
}

public func GetHandItem(int i)
{
	// carrying a carry heavy item always returns said item. (he holds it in both hands, after all!)
	if (IsCarryingHeavy())
		return GetCarryHeavy();
	return _inherited(i, ...);
}

// Delete internal variables
public func Ejection(object obj)
{
	// carry heavy special treatment
	if(obj == GetCarryHeavy())
	{
		StopCarryHeavy();
		return true;
	}
	return _inherited(obj,...);
}

// Delete internal variables
public func ContentsDestruction(object obj)
{
	// check if it was carryheavy
	if(obj == GetCarryHeavy())
	{
		StopCarryHeavy();
	}

	return _inherited(obj, ...);
}

/* Overloads for Clonk Control */

public func GetExtraInteractions()
{
	var functions = _inherited(...);

	// dropping carry heavy
	if(IsCarryingHeavy() && GetAction() == "Walk")
	{
		var ch = GetCarryHeavy();
		PushBack(functions, {Fn = "DropCarryHeavy", Description=ch->GetDropDescription(), Object=this, IconName="", IconID=Icon_LetGo, Priority=1});
	}
	return functions;
}

/* Carry heavy stuff */

/** Tells the clonk that he is carrying the given carry heavy object */
public func CarryHeavy(object target)
{
	if(!target)
		return;
	// actually.. is it a carry heavy object?
	if(!target->~IsCarryHeavy())
		return;
	// only if not carrying a heavy objcet already
	if(IsCarryingHeavy())
		return;

	lib_carryheavy_obj = target;

	if(target->Contained() != this)
		target->Enter(this);

	// Update attach stuff
	this->~OnSlotFull();
	
	// Do callbacks to control effects for this clonk that a carry heavy object has been picked up.
	var count = GetEffectCount("*Control*", this), control_effect;
	while (count--)
	{
		control_effect = GetEffect("*Control*", this, count);
		if (control_effect)
			EffectCall(this, control_effect, "OnCarryHeavyPickUp", target);
	}

	return true;
}

/** Drops the carried heavy object, if any */
public func DropCarryHeavy()
{
	// only if actually possible
	if(!IsCarryingHeavy())
		return;

	DoDropCarryHeavy(GetCarryHeavy());
	StopCarryHeavy();

	return true;
}

// Internal function to clear carryheavy-status
private func StopCarryHeavy()
{
	if(!IsCarryingHeavy())
		return;

	lib_carryheavy_obj = nil;
	this->~OnSlotEmpty();
}

/* Lifting / dropping effect */

local lib_carryheavy_lifttime = 45;

private func DoLiftCarryHeavy(object obj)
{
	if (!obj || !obj->~IsCarryHeavy())
		return;
	if (obj->Contained() != this)
		return;
	// If inside something or not walking, skip the animation
	if (Contained() || GetAction() != "Walk" || this.BlockCarryHeavyPickUpAnimation)
		return;
	AddEffect("IntLiftHeavy", this, 1, 1, this, nil, obj);
}

private func DoDropCarryHeavy(object obj)
{
	if (!obj || !obj->~IsCarryHeavy())
		return;
	if (obj->Contained() != this)
		return;
	// If inside something or not walking, skip the animation
	if (Contained() || GetAction() != "Walk")
		return;
	AddEffect("IntDropHeavy", this, 1, 1, this, nil, obj);
}

private func FxIntLiftHeavyStart(object me, proplist effect, bool tmp, object to_lift)
{
	//Stop the clonk from moving, and tell the clonk's control library
	//it now has a hand action
	me->SetTurnForced(GetDir());
	me->SetHandAction(1);
	SetAction("Stand");
	//Stop the clonk if he is moving
	if(GetXDir() != 0) SetXDir();

	//Attach the mesh of the object. It is not displayed normally because the
	//hands are told they have an action in the next few lines
	effect.mesh = AttachMesh(to_lift, "pos_tool1", to_lift->GetCarryBone(), to_lift->~GetCarryTransform(this));

	//Play the animation of the clonk picking up the object
	effect.anim = PlayAnimation("CarryArmsPickup", CLONK_ANIM_SLOT_Arms, Anim_Linear(0,0, GetAnimationLength("CarryArmsPickup"), lib_carryheavy_lifttime, ANIM_Remove), Anim_Const(1000));

	effect.obj = to_lift;
}

private func FxIntLiftHeavyTimer(object me, proplist effect, int time)
{
	//If the clonk moves, he'll stop lifting and drop the object
	if(time < lib_carryheavy_lifttime)
	{
		// first 2/3 of time, clonk will drop the object
		if(time < lib_carryheavy_lifttime * 2 / 3)
		{
			if(GetAction() != "Stand" || me->IsJumping() || Abs(GetXDir()) > 0)
			{
				effect.fail = true;
				return FX_Execute_Kill;
			}
		}
		else
		{
			if(GetAction() != "Stand")
				return FX_Execute_Kill;
		}
	}
	//When the clonk has finished lifting, remove movement-restrictions
	if(time >= lib_carryheavy_lifttime)
		return FX_Execute_Kill;
	// Object got moved out during lifting
	if(!effect.obj || effect.obj->Contained() != this)
		return FX_Execute_Kill;
}

private func FxIntLiftHeavyStop(object me, proplist effect)
{
	// If failed, drop the object
	if(effect.fail && effect.obj && effect.obj->Contained() == this)
		effect.obj->Exit(0,9);

	DetachMesh(effect.mesh);
	StopAnimation(effect.anim);
	me->SetTurnForced(-1);
	me->SetHandAction(0);
	if(GetAction() == "Stand") SetAction("Walk");
}

private func FxIntDropHeavyStart(object me, proplist effect, bool tmp, object to_lift)
{
	if(GetEffect("IntCarryHeavy"))
		RemoveEffect("IntCarryHeavy", this, nil, true);

	//Stop the clonk from moving, and tell the clonk's control library
	//it now has a hand action
	me->SetTurnForced(GetDir());
	me->SetHandAction(1);
	SetAction("Stand");
	//Stop the clonk if he is moving
	if(GetXDir() != 0) SetXDir();

	//Attach the mesh of the object. It is not displayed normally because the
	//hands are told they have an action in the next few lines
	effect.mesh = AttachMesh(to_lift, "pos_tool1", to_lift->GetCarryBone(), to_lift->~GetCarryTransform(this));

	//Play the animation of the clonk setting down the object
	effect.anim = PlayAnimation("CarryArmsPickup", CLONK_ANIM_SLOT_Arms, Anim_Linear(GetAnimationLength("CarryArmsPickup"), GetAnimationLength("CarryArmsPickup"), 0, lib_carryheavy_lifttime, ANIM_Remove), Anim_Const(1000));

	effect.obj = to_lift;
}

private func FxIntDropHeavyTimer(object me, proplist effect, int time)
{
	if (time >= lib_carryheavy_lifttime)
		return FX_Execute_Kill;
	if (GetAction() != "Stand")
		return FX_Execute_Kill;
	if (!effect.obj)
		return FX_Execute_Kill;
	if (effect.obj->Contained() != this)
		return FX_Execute_Kill;
}

private func FxIntDropHeavyStop(object me, proplist effect)
{
	// Drop the object
	if(effect.obj && effect.obj->Contained() == this)
		effect.obj->Exit(0,9);

	DetachMesh(effect.mesh);
	StopAnimation(effect.anim);
	me->SetTurnForced(-1);
	me->SetHandAction(0);
	if(GetAction() == "Stand") SetAction("Walk");
}