forked from Mirrors/openclonk
260 lines
6.5 KiB
C
260 lines
6.5 KiB
C
/*
|
|
Lift Tower Rope
|
|
Author: Randrian, Clonkonaut
|
|
|
|
The rope used for the lift tower.
|
|
Connect(obj1, obj2) connects two objects
|
|
BreakRope() breaks the rope
|
|
*/
|
|
|
|
#include Library_Rope
|
|
|
|
static const Weight = 1;
|
|
static const Library_Rope_MAXLENGTH = 1000;
|
|
|
|
// Call this to break the rope.
|
|
public func BreakRope(bool silent)
|
|
{
|
|
if(length == -1) return;
|
|
length = -1;
|
|
var act1 = objects[0][0];
|
|
var act2 = objects[1][0];
|
|
SetAction("Idle");
|
|
// notify action targets.
|
|
if (act1 != nil && !silent)
|
|
act1->~OnRopeBreak();
|
|
if (act2 != nil && !silent)
|
|
act2->~OnRopeBreak();
|
|
RemoveRope();
|
|
RemoveObject();
|
|
return;
|
|
}
|
|
|
|
/* --------------------- Callbacks form the rope ---------------------- */
|
|
|
|
/* To be overloaded for special segment behaviour */
|
|
private func CreateSegment(int index, object previous)
|
|
{
|
|
if(index == 0) return;
|
|
var segment;
|
|
segment = CreateObject(LiftTower_Rope);
|
|
return segment;
|
|
}
|
|
|
|
/*-- Rope connecting --*/
|
|
|
|
// Connects two objects to the rope, but the length will vary on their positions.
|
|
public func Connect(object obj1, object obj2, int max_length)
|
|
{
|
|
StartRopeConnect(obj1, obj2);
|
|
if (!max_length) max_length = Library_Rope_MAXLENGTH;
|
|
SetMaxLength(max_length);
|
|
SetFixed(true, false);
|
|
|
|
SetAction("Hide");
|
|
|
|
AddEffect("IntHang", this, 1, 1, this);
|
|
return;
|
|
}
|
|
|
|
public func Reconnect(object reconnect)
|
|
{
|
|
objects[1][0] = reconnect;
|
|
}
|
|
|
|
public func GetConnectStatus() { return !length_auto; }
|
|
|
|
public func HookRemoved()
|
|
{
|
|
BreakRope();
|
|
}
|
|
|
|
func FxIntHangTimer() { TimeStep(); }
|
|
|
|
local last_point;
|
|
|
|
func UpdateLines()
|
|
{
|
|
var oldangle;
|
|
for(var i=1; i < ParticleCount; i++)
|
|
{
|
|
// Update the Position of the Segment
|
|
segments[i]->SetPosition(GetPartX(i), GetPartY(i));
|
|
|
|
// Calculate the angle to the previous segment
|
|
var angle = Angle(particles[i][0][0], particles[i][0][1], particles[i-1][0][0], particles[i-1][0][1]);
|
|
|
|
// Draw the left line
|
|
var start = particles[i-1][0][:];
|
|
var end = particles[i][0][:];
|
|
|
|
if(i == 1 && ParticleCount > 2)
|
|
{
|
|
angle = Angle(particles[2][0][0], particles[2][0][1], particles[0][0][0], particles[0][0][1]);
|
|
end = particles[0][0][:];
|
|
end[0] += -Sin(angle, 45*Rope_Precision/10);
|
|
end[1] += +Cos(angle, 45*Rope_Precision/10);
|
|
segments[i]->SetGraphics("Invis");
|
|
}
|
|
|
|
if(i == 2)
|
|
{
|
|
angle = Angle(particles[2][0][0], particles[2][0][1], particles[0][0][0], particles[0][0][1]);
|
|
start = particles[0][0][:];
|
|
start[0] += -Sin(angle, 45*Rope_Precision/10);
|
|
start[1] += +Cos(angle, 45*Rope_Precision/10);
|
|
segments[i]->SetGraphics("Short");
|
|
}
|
|
|
|
var diff = Vec_Sub(end,start);
|
|
var point = Vec_Add(start, Vec_Div(diff, 2));
|
|
var diffangle = Vec_Angle(diff, [0,0]);
|
|
var length = Vec_Length(diff)*1000/Rope_Precision/10;
|
|
|
|
if(i == ParticleCount-1)
|
|
{
|
|
var old = particles[i-2][0][:];
|
|
var old_diff = Vec_Sub(start,old);
|
|
var o_length = Vec_Length(old_diff)*1000/Rope_Precision/10;
|
|
if(!o_length) diff = old_diff;
|
|
else diff = Vec_Div(Vec_Mul(old_diff, length),o_length);
|
|
diffangle = Vec_Angle(diff, [0,0]);
|
|
point = Vec_Add(start, Vec_Div(diff, 2));
|
|
last_point = point;
|
|
}
|
|
|
|
segments[i]->SetGraphics(nil);
|
|
SetLineTransform(segments[i], -diffangle, point[0]*10-GetPartX(i)*1000,point[1]*10-GetPartY(i)*1000, length );
|
|
|
|
// Remember the angle
|
|
oldangle = angle;
|
|
}
|
|
}
|
|
|
|
func GetHookAngle()
|
|
{
|
|
if(ParticleCount > 3)
|
|
return Angle(particles[-2][0][0], particles[-2][0][1], particles[-3][0][0], particles[-3][0][1])+180;
|
|
}
|
|
|
|
func SetLineTransform(obj, num r, num xoff, num yoff, num length, int layer, int MirrorSegments) {
|
|
if(!MirrorSegments) MirrorSegments = 1;
|
|
var fsin=Sin(r, 1000), fcos=Cos(r, 1000);
|
|
// set matrix values
|
|
obj->SetObjDrawTransform (
|
|
+fcos*MirrorSegments, +fsin*length/1000, xoff,
|
|
-fsin*MirrorSegments, +fcos*length/1000, yoff,layer
|
|
);
|
|
}
|
|
|
|
/* Overload */
|
|
|
|
local pull_position, pull_faults, pull_frame;
|
|
|
|
// Altered to not just pull the objects into the rope's direction but
|
|
// if the object doesn't not move it is tried to shake it free by applying
|
|
// impulses to every direction
|
|
func ForcesOnObjects()
|
|
{
|
|
if(!length) return;
|
|
|
|
var redo = LengthAutoTryCount();
|
|
while(length_auto && redo)
|
|
{
|
|
var speed = Vec_Length(Vec_Sub(particles[-1][0], particles[-1][1]));
|
|
if(length == GetMaxLength())
|
|
{
|
|
if(ObjContact(objects[1][0]))
|
|
speed = 40;
|
|
else speed = 100;
|
|
}
|
|
if(speed > 150) DoLength(1);
|
|
else if(speed < 50) DoLength(-1);
|
|
else redo = 0;
|
|
if(redo) redo --;
|
|
}
|
|
var j = 0;
|
|
if(PullObjects() )
|
|
for(var i = 0; i < 2; i++)
|
|
{
|
|
if(i == 1) j = ParticleCount-1;
|
|
var obj = objects[i][0];
|
|
|
|
if(obj == nil || objects[i][1] == 0) continue;
|
|
|
|
if(obj->Contained()) obj = obj->Contained();
|
|
|
|
if( (obj->GetAction() == "Walk" || obj->GetAction() == "Scale" || obj->GetAction() == "Hangle"))
|
|
obj->SetAction("Jump");
|
|
if( obj->GetAction() == "Climb")
|
|
obj->SetAction("Jump");
|
|
|
|
var xdir = BoundBy(particles[j][0][0]-particles[j][1][0], -100, 100);
|
|
var ydir = particles[j][0][1]-particles[j][1][1];
|
|
|
|
if (!obj->GetContact(-1))
|
|
ydir = BoundBy(ydir, -120, 120);
|
|
|
|
if (pull_position && pull_frame != FrameCounter() && !Distance(pull_position[0], pull_position[1], obj->GetX(), obj->GetY()))
|
|
{
|
|
if (!pull_faults)
|
|
{
|
|
ydir *= -1;
|
|
pull_faults++;
|
|
}
|
|
else
|
|
{
|
|
xdir *= -1;
|
|
pull_faults = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pull_position = [obj->GetX(), obj->GetY()];
|
|
pull_faults = 0;
|
|
}
|
|
pull_frame = FrameCounter();
|
|
|
|
obj->SetXDir( xdir, Rope_Precision);
|
|
obj->SetYDir( obj->GetYDir(Rope_Precision) + ydir, Rope_Precision);
|
|
}
|
|
}
|
|
|
|
// Altered to function in 'ConnectPull' mode
|
|
public func ConstraintObjects()
|
|
{
|
|
if(length < GetMaxLength()) // in the rope library this is
|
|
{ // if(length_auto && length < GetMaxLength())
|
|
for(var i = 0, i2 = 0; i < 2; i++ || i2--)
|
|
SetParticleToObject(i2, i);
|
|
}
|
|
}
|
|
|
|
// This is called constantly by the lift tower as long as something is reeled in
|
|
// Altered so the rope will not get shorter than the distance between the tower
|
|
// and the hooked up object
|
|
public func DoLength(int dolength)
|
|
{
|
|
var obj = objects[0][0]; // First connected object
|
|
var obj2 = objects[1][0]; // Second connected object
|
|
// I guess this is not possible but just to be sure
|
|
if (!obj || !obj2) return _inherited(dolength);
|
|
if (obj->Contained()) obj = obj->Contained();
|
|
if (obj2->Contained()) obj2 = obj2->Contained();
|
|
|
|
// Line would be shorter than the distance? Do nothing
|
|
if (dolength < 0 && ObjectDistance(obj, obj2) > GetLineLength()/100) return;
|
|
return _inherited(dolength);
|
|
}
|
|
|
|
func Definition(def)
|
|
{
|
|
def.LineColors = [RGB(66,33,00), RGB(66,33,00)];
|
|
}
|
|
local ActMap = {
|
|
Hide = {
|
|
Prototype = Action,
|
|
Name = "Hide",
|
|
},
|
|
};
|
|
local Name = "$Name$"; |