forked from Mirrors/openclonk
279 lines
6.9 KiB
C
279 lines
6.9 KiB
C
/*--
|
|
TeleGlove
|
|
Author: Ringwaul
|
|
|
|
Move objects remotely.
|
|
--*/
|
|
|
|
local reach;
|
|
local radius; //actual effect radius to grab objects
|
|
local radiusparticle; //radius of particles around object
|
|
|
|
local aiming;
|
|
local anim_spin;
|
|
|
|
local iAngle;
|
|
local aim_anim;
|
|
local carry_bone;
|
|
|
|
local target_object;
|
|
|
|
protected func Initialize()
|
|
{
|
|
reach = 150;
|
|
radius = 60;
|
|
radiusparticle = radius / 4;
|
|
}
|
|
|
|
public func GetCarryMode() { return CARRY_HandBack; }
|
|
public func GetCarrySpecial(clonk) { return carry_bone; }
|
|
public func GetCarryBone() { return "main"; }
|
|
public func GetCarryTransform()
|
|
{
|
|
//Left hand's bone is different? I don't know, but this is a work-around.
|
|
if(carry_bone == "pos_hand1") return Trans_Rotate(180,0,1,0);
|
|
return Trans_Rotate(-90,0,1,0);
|
|
}
|
|
|
|
protected func HoldingEnabled() { return true; }
|
|
|
|
protected func ControlUseStart(object clonk, ix, iy)
|
|
{
|
|
// if the clonk doesn't have an action where he can use it's hands do nothing
|
|
if(!clonk->HasHandAction() || (!clonk->IsWalking() && !clonk->IsJumping()))
|
|
return true;
|
|
else
|
|
{
|
|
StartUsage(clonk);
|
|
UpdateGloveAngle(clonk, ix, iy);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
private func StartUsage(object clonk)
|
|
{
|
|
var hand;
|
|
// which animation to use? (which hand)
|
|
if(clonk->GetHandPosByItemPos(clonk->GetItemPos(this)) == 0)
|
|
{
|
|
carry_bone = "pos_hand2";
|
|
hand = "AimArmsGeneric.R";
|
|
}
|
|
else
|
|
{
|
|
carry_bone = "pos_hand1";
|
|
hand = "AimArmsGeneric.L";
|
|
}
|
|
|
|
aiming = 1;
|
|
|
|
aim_anim = clonk->PlayAnimation(hand, 10, Anim_Const(clonk->GetAnimationLength(hand)/2), Anim_Const(1000));
|
|
clonk->UpdateAttach();
|
|
|
|
|
|
//Animations and effects for TeleGlove
|
|
Sound("Electrical",nil,nil,nil,+1);
|
|
PlayAnimation("Opening", -5, Anim_Linear(0,0,GetAnimationLength("Opening"), 10, ANIM_Hold), Anim_Const(1000));
|
|
anim_spin = PlayAnimation("Spin",5, Anim_Linear(0,0,GetAnimationLength("Spin"), 40, ANIM_Loop), Anim_Const(1000));
|
|
}
|
|
|
|
private func EndUsage(object clonk)
|
|
{
|
|
carry_bone = nil;
|
|
aim_anim = nil;
|
|
iAngle = 0;
|
|
clonk->StopAnimation(clonk->GetRootAnimation(10));
|
|
clonk->UpdateAttach();
|
|
}
|
|
|
|
// Update the glove aim angle
|
|
private func UpdateGloveAngle(object clonk, int x, int y)
|
|
{
|
|
var angle=Normalize(Angle(0,0, x,y),-180);
|
|
angle=BoundBy(angle,-150,150);
|
|
|
|
if(clonk->GetDir() == DIR_Left)
|
|
{
|
|
if(angle > 0) return;
|
|
}
|
|
else
|
|
{
|
|
if(angle < 0) return;
|
|
}
|
|
|
|
iAngle=angle;
|
|
|
|
// var weight = 0;
|
|
// if( Abs(iAngle) > 90) weight = 1000*( Abs(iAngle)-60 )/90;
|
|
|
|
clonk->SetAnimationPosition(aim_anim, Anim_Const(Abs(iAngle) * 11111/1000));
|
|
}
|
|
|
|
public func ControlUseHolding(object clonk, ix, iy)
|
|
{
|
|
if(!clonk->HasHandAction() || !aiming || (!clonk->IsWalking() && !clonk->IsJumping()))
|
|
{
|
|
CancelUse(clonk);
|
|
return 1;
|
|
}
|
|
|
|
UpdateGloveAngle(clonk, ix, iy);
|
|
|
|
//effects
|
|
var xs = Sin(Random(359),radiusparticle/2);
|
|
var ys = -Cos(Random(359),radiusparticle/2);
|
|
var anglep = Angle(0,0,ix,iy);
|
|
var distp = Distance(0,0,ix,iy);
|
|
|
|
var particles;
|
|
if (Random(2)) particles = Particles_ElectroSpark1();
|
|
else particles = Particles_ElectroSpark2();
|
|
|
|
if(distp < reach)
|
|
{
|
|
//Particles moving towards object
|
|
CreateParticle("ElectroSpark", ix + xs, iy + ys, PV_Random(-xs/2, -xs/4), PV_Random(-ys/2, -ys/4), PV_Random(5, 10), particles, 5);
|
|
|
|
//Particles emitting from clonk
|
|
var wp = 1;
|
|
if(Random(2)) wp = -1;
|
|
var xp = anglep + RandomX(-3, 3);
|
|
var yp = anglep + RandomX(-3, 3);
|
|
var xdir = Sin(xp, 10);
|
|
var ydir = -Cos(yp, 10);
|
|
var distance = Random(distp);
|
|
CreateParticle("ElectroSpark", Sin(xp, distance), -Cos(yp, distance), PV_Random(xdir - 5, xdir + 5), PV_Random(ydir - 2, ydir + 2), PV_Random(5, 10), particles, 5);
|
|
}
|
|
|
|
var target;
|
|
if(target_object)
|
|
{
|
|
if(Distance(target_object->GetX(), target_object->GetY(), clonk->GetX() + ix, clonk->GetY() + iy) > radius ||
|
|
Distance(target_object->GetX(), target_object->GetY(), clonk->GetX(), clonk->GetY()) > reach)
|
|
{
|
|
LostTargetObject(target);
|
|
target_object = nil;
|
|
}
|
|
}
|
|
|
|
if(!target_object)
|
|
{
|
|
target = FindObject(Find_Exclude(this),
|
|
Find_NoContainer(),
|
|
Find_Category(C4D_Object),
|
|
Find_And(Find_Distance(radius, ix, iy),
|
|
Find_Distance(reach - 15)),
|
|
Sort_Distance(ix,iy));
|
|
|
|
if(target)
|
|
{
|
|
GainedTargetObject(target);
|
|
target_object = target;
|
|
}
|
|
}
|
|
|
|
//Has the object recently been thrown by another player?
|
|
var e = GetEffect("TeleGloveReleased", target_object);
|
|
var old_controller; if(e) old_controller = e.controller;
|
|
if(target_object
|
|
&& !target_object->Stuck()
|
|
&& (!e || old_controller == Contained()->GetOwner()))
|
|
{
|
|
var angle = Angle(target_object->GetX(), target_object->GetY(), clonk->GetX() + ix, clonk->GetY() + iy);
|
|
var dist = Distance(target_object->GetX(), target_object->GetY(), clonk->GetX() + ix, clonk->GetY() + iy);
|
|
var speed = dist;
|
|
|
|
//Set speed
|
|
target_object->SetSpeed(Sin(angle, speed), -Cos(angle, speed));
|
|
|
|
//Particles emitting from object
|
|
target_object->CreateParticle("ElectroSpark", 0, 0, PV_Random(xs/8, xs/10), PV_Random(ys/8, ys/10), PV_Random(5, 10), particles, 5);
|
|
}
|
|
else
|
|
LostTargetObject(target_object);
|
|
return 1;
|
|
}
|
|
|
|
public func GainedTargetObject(object target)
|
|
{
|
|
if (!GetEffect("TeleGloveWeight", target))
|
|
{
|
|
//Who holds the object? For killtracing
|
|
target->SetController(Contained()->GetController());
|
|
target->~OnTeleGloveControl(this);
|
|
AddEffect("TeleGloveWeight", target, 1, 0, target);
|
|
return 1;
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
public func LostTargetObject(object target)
|
|
{
|
|
RemoveEffect("TeleGloveWeight", target);
|
|
var effect = AddEffect("TeleGloveReleased", target, 1, 35*5);
|
|
effect.controller = Contained()->GetController();
|
|
}
|
|
|
|
global func FxTeleGloveReleasedStart(object target, effect)
|
|
{
|
|
effect.t0 = FrameCounter();
|
|
return;
|
|
}
|
|
|
|
global func FxTeleGloveWeightStart(object target, int num)
|
|
{
|
|
target->SetMass(target->GetMass()/2);
|
|
}
|
|
|
|
global func FxTeleGloveWeightStop(object target, int num, int reason, bool temp)
|
|
{
|
|
target->SetMass(target->GetDefCoreVal("Mass", "DefCore"));
|
|
}
|
|
|
|
// Damaging Clonks with moving objects makes this tool stupidly strong. So it's blocked
|
|
// while moving the object and a few frames after release
|
|
global func FxTeleGloveWeightQueryHitClonk(object target, fx, object clonk) { return true; }
|
|
global func FxTeleGloveReleasedQueryHitClonk(object target, fx, object clonk) { return FrameCounter()-fx.t0 <= 5; }
|
|
|
|
protected func ControlUseStop(object clonk, ix, iy)
|
|
{
|
|
CancelUse(clonk);
|
|
return 1;
|
|
}
|
|
|
|
protected func ControlUseCancel(object clonk, int ix, int iy)
|
|
{
|
|
CancelUse(clonk);
|
|
}
|
|
|
|
protected func CancelUse(object clonk)
|
|
{
|
|
EndUsage(clonk);
|
|
Sound("Electrical",nil,nil,nil,-1);
|
|
if(aiming = 1) PlayAnimation("Closing", -5, Anim_Linear(0,0,GetAnimationLength("Closing"), 10, ANIM_Hold), Anim_Const(1000));
|
|
StopAnimation(anim_spin);
|
|
aiming = 0;
|
|
if(target_object) LostTargetObject(target_object);
|
|
target_object = nil;
|
|
return 1;
|
|
}
|
|
|
|
func Hit()
|
|
{
|
|
Sound("GeneralHit?");
|
|
}
|
|
|
|
func IsInventorProduct() { return true; }
|
|
|
|
func Definition(def) {
|
|
SetProperty("PictureTransformation",Trans_Rotate(-60,1,0,1),def);
|
|
}
|
|
|
|
local Name = "$Name$";
|
|
local UsageHelp = "$UsageHelp$";
|
|
local Description = "$Description$";
|
|
local Collectible = 1;
|
|
local Rebuy = true;
|