openclonk/planet/Experimental.ocd/LiftTower.ocd/Rope.ocd/Script.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$";