clean up and small speed gain for rope library

Also clean up for related objects, this is still work in progress to fix some bugs and get more speed up.
shapetextures
Maikel de Vries 2015-12-08 16:43:52 +01:00
parent fb5a910d0c
commit 64a4d12683
9 changed files with 640 additions and 667 deletions

View File

@ -15,10 +15,10 @@ 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];
if(lib_rope_length == -1) return;
lib_rope_length = -1;
var act1 = lib_rope_objects[0][0];
var act2 = lib_rope_objects[1][0];
SetAction("Idle");
// notify action targets.
if (act1 != nil && !silent)
@ -59,10 +59,10 @@ public func Connect(object obj1, object obj2, int max_length)
public func Reconnect(object reconnect)
{
objects[1][0] = reconnect;
lib_rope_objects[1][0] = reconnect;
}
public func GetConnectStatus() { return !length_auto; }
public func GetConnectStatus() { return !lib_rope_length_auto; }
public func HookRemoved()
{
@ -76,34 +76,34 @@ local last_point;
func UpdateLines()
{
var oldangle;
for(var i=1; i < ParticleCount; i++)
for(var i=1; i < lib_rope_particle_count; i++)
{
// Update the Position of the Segment
segments[i]->SetPosition(GetPartX(i), GetPartY(i));
lib_rope_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]);
var angle = Angle(lib_rope_particles[i][0][0], lib_rope_particles[i][0][1], lib_rope_particles[i-1][0][0], lib_rope_particles[i-1][0][1]);
// Draw the left line
var start = particles[i-1][0][:];
var end = particles[i][0][:];
var start = lib_rope_particles[i-1][0][:];
var end = lib_rope_particles[i][0][:];
if(i == 1 && ParticleCount > 2)
if(i == 1 && lib_rope_particle_count > 2)
{
angle = Angle(particles[2][0][0], particles[2][0][1], particles[0][0][0], particles[0][0][1]);
end = particles[0][0][:];
angle = Angle(lib_rope_particles[2][0][0], lib_rope_particles[2][0][1], lib_rope_particles[0][0][0], lib_rope_particles[0][0][1]);
end = lib_rope_particles[0][0][:];
end[0] += -Sin(angle, 45*LIB_ROPE_Precision/10);
end[1] += +Cos(angle, 45*LIB_ROPE_Precision/10);
segments[i]->SetGraphics("Invis");
lib_rope_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][:];
angle = Angle(lib_rope_particles[2][0][0], lib_rope_particles[2][0][1], lib_rope_particles[0][0][0], lib_rope_particles[0][0][1]);
start = lib_rope_particles[0][0][:];
start[0] += -Sin(angle, 45*LIB_ROPE_Precision/10);
start[1] += +Cos(angle, 45*LIB_ROPE_Precision/10);
segments[i]->SetGraphics("Short");
lib_rope_segments[i]->SetGraphics("Short");
}
var diff = Vec_Sub(end,start);
@ -111,9 +111,9 @@ func UpdateLines()
var diffangle = Vec_Angle(diff, [0,0]);
var length = Vec_Length(diff)*1000/LIB_ROPE_Precision/10;
if(i == ParticleCount-1)
if(i == lib_rope_particle_count-1)
{
var old = particles[i-2][0][:];
var old = lib_rope_particles[i-2][0][:];
var old_diff = Vec_Sub(start,old);
var o_length = Vec_Length(old_diff)*1000/LIB_ROPE_Precision/10;
if(!o_length) diff = old_diff;
@ -123,8 +123,8 @@ func UpdateLines()
last_point = point;
}
segments[i]->SetGraphics(nil);
SetLineTransform(segments[i], -diffangle, point[0]*10-GetPartX(i)*1000,point[1]*10-GetPartY(i)*1000, length );
lib_rope_segments[i]->SetGraphics(nil);
SetLineTransform(lib_rope_segments[i], -diffangle, point[0]*10-GetPartX(i)*1000,point[1]*10-GetPartY(i)*1000, length );
// Remember the angle
oldangle = angle;
@ -133,8 +133,8 @@ func UpdateLines()
func GetHookAngle()
{
if(ParticleCount > 3)
return Angle(particles[-2][0][0], particles[-2][0][1], particles[-3][0][0], particles[-3][0][1])+180;
if(lib_rope_particle_count > 3)
return Angle(lib_rope_particles[-2][0][0], lib_rope_particles[-2][0][1], lib_rope_particles[-3][0][0], lib_rope_particles[-3][0][1])+180;
}
func SetLineTransform(obj, int r, int xoff, int yoff, int length, int layer, int MirrorSegments) {
@ -156,15 +156,15 @@ local pull_position, pull_faults, pull_frame;
// impulses to every direction
func ForcesOnObjects()
{
if(!length) return;
if(!lib_rope_length) return;
var redo = LengthAutoTryCount();
while(length_auto && redo)
while(lib_rope_length_auto && redo)
{
var speed = Vec_Length(Vec_Sub(particles[-1][0], particles[-1][1]));
if(length == GetMaxLength())
var speed = Vec_Length(Vec_Sub(lib_rope_particles[-1][0], lib_rope_particles[-1][1]));
if(lib_rope_length == GetMaxLength())
{
if(ObjContact(objects[1][0]))
if(ObjContact(lib_rope_objects[1][0]))
speed = 40;
else speed = 100;
}
@ -177,10 +177,10 @@ func ForcesOnObjects()
if(PullObjects() )
for(var i = 0; i < 2; i++)
{
if(i == 1) j = ParticleCount-1;
var obj = objects[i][0];
if(i == 1) j = lib_rope_particle_count-1;
var obj = lib_rope_objects[i][0];
if(obj == nil || objects[i][1] == 0) continue;
if(obj == nil || lib_rope_objects[i][1] == 0) continue;
if(obj->Contained()) obj = obj->Contained();
@ -189,8 +189,8 @@ func ForcesOnObjects()
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];
var xdir = BoundBy(lib_rope_particles[j][0][0]-lib_rope_particles[j][1][0], -100, 100);
var ydir = lib_rope_particles[j][0][1]-lib_rope_particles[j][1][1];
if (!obj->GetContact(-1))
ydir = BoundBy(ydir, -120, 120);
@ -223,8 +223,8 @@ func ForcesOnObjects()
// Altered to function in 'ConnectPull' mode
public func ConstraintObjects()
{
if(length < GetMaxLength()) // in the rope library this is
{ // if(length_auto && length < GetMaxLength())
if(lib_rope_length < GetMaxLength()) // in the rope library this is
{
for(var i = 0, i2 = 0; i < 2; i++ || i2--)
SetParticleToObject(i2, i);
}
@ -235,8 +235,8 @@ public func ConstraintObjects()
// 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
var obj = lib_rope_objects[0][0]; // First connected object
var obj2 = lib_rope_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();

View File

@ -1,28 +1,23 @@
/*
/**
Grapple Rope
Author: Randrian
The rope used for grappling devices.
Connect(obj1, obj2) connects two objects
BreakRope() breaks the rope
DrawIn() draws the hook in
The rope used for grappling devices. Connect(obj1, obj2) connects two objects,
BreakRope() breaks the rope, DrawIn() draws the hook in.
@author Randrian
*/
#include Library_Rope
//static const Rope_Iterations = 10;
//static const Rope_Precision = 100;
//static const Rope_PointDistance = 10;
static const Weight = 1;
// Call this to break the rope.
public func BreakRope()
{
if(length == -1) return;
length = -1;
var act1 = objects[0][0];
var act2 = objects[1][0];
if(lib_rope_length == -1) return;
lib_rope_length = -1;
var act1 = lib_rope_objects[0][0];
var act2 = lib_rope_objects[1][0];
SetAction("Idle");
// notify action targets.
if (act1 != nil)
@ -60,7 +55,7 @@ public func Connect(object obj1, object obj2)
return;
}
public func GetConnectStatus() { return !length_auto; }
public func GetConnectStatus() { return !lib_rope_length_auto; }
local HoockAnchored;
local DrawingIn;
@ -71,26 +66,24 @@ public func HockAnchored(bool pull)
HoockAnchored = 1;
}
//func LengthAutoTryCount() { if(!HoockAnchored && !DrawingIn) return 10; return 5; }
public func HookRemoved()
{
var new_hook = CreateObjectAbove(GrappleHook);
new_hook->New(objects[1][0]->Contained(), this);
objects[1][0]->SetHook(new_hook);
objects[0][0] = new_hook;
new_hook->New(lib_rope_objects[1][0]->Contained(), this);
lib_rope_objects[1][0]->SetHook(new_hook);
lib_rope_objects[0][0] = new_hook;
DrawIn();
}
/* Callback form the rope library */
public func MaxLengthReached()
{
var clonk = objects[1][0];
var clonk = lib_rope_objects[1][0];
if(clonk->Contained()) clonk = clonk->Contained();
if(!HoockAnchored)
{
for(var i = 0; i < ParticleCount; i++)
particles[i][1] = particles[i][0][:];
for(var i = 0; i < lib_rope_particle_count; i++)
lib_rope_particles[i][1] = lib_rope_particles[i][0][:];
DrawIn(true);
}
}
@ -98,16 +91,16 @@ public func MaxLengthReached()
/* for swinging */
func DoSpeed(int value)
{
var speed = particles[-1][0][0]-particles[-1][1][0];
var speed = lib_rope_particles[-1][0][0]-lib_rope_particles[-1][1][0];
if(speed*value > 0) value += speed/10;
particles[-1][1][0] -= value;
lib_rope_particles[-1][1][0] -= value;
}
func FxIntHangTimer() { TimeStep(); }
func FxDrawInTimer()
{
if(length < 15)
if(lib_rope_length < 15)
{
BreakRope();
return -1;
@ -115,8 +108,8 @@ func FxDrawInTimer()
DoLength(-5);
if(!HoockAnchored)
{
for(var i = 0; i < ParticleCount; i++)
particles[i][1] = particles[i][0][:];//Vec_Add(particles[i][0],Vec_Div(Vec_Sub(particles[i][0],particles[i][1]), 2));
for(var i = 0; i < lib_rope_particle_count; i++)
lib_rope_particles[i][1] = lib_rope_particles[i][0][:];
DoLength(-3);
}
}
@ -128,10 +121,10 @@ func DrawIn(bool no_control)
{
AddEffect("DrawIn", this, 1, 1, this);
SetFixed(0, 1);
objects[0][0]->SetXDir();
objects[0][0]->SetYDir();
lib_rope_objects[0][0]->SetXDir();
lib_rope_objects[0][0]->SetYDir();
ConnectPull();
var clonk = objects[1][0];
var clonk = lib_rope_objects[1][0];
if (clonk->Contained())
clonk = clonk->Contained();
if (!no_control)
@ -146,10 +139,10 @@ func DrawIn(bool no_control)
func AdjustClonkMovement()
{
var clonk = objects[1][0];
var clonk = lib_rope_objects[1][0];
if(clonk->Contained()) clonk = clonk->Contained();
var rope_vector = Vec_Sub(particles[-1][0], particles[-2][0]);
var rope_vector = Vec_Sub(lib_rope_particles[-1][0], lib_rope_particles[-2][0]);
var clonk_speed = [clonk->GetXDir(LIB_ROPE_Precision), clonk->GetYDir(LIB_ROPE_Precision)];
@ -167,30 +160,30 @@ local last_point;
func UpdateLines()
{
var oldangle;
for(var i=1; i < ParticleCount; i++)
for(var i=1; i < lib_rope_particle_count; i++)
{
// Update the Position of the Segment
segments[i]->SetPosition(GetPartX(i), GetPartY(i));
lib_rope_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]);
var angle = Angle(lib_rope_particles[i][0][0], lib_rope_particles[i][0][1], lib_rope_particles[i-1][0][0], lib_rope_particles[i-1][0][1]);
// Draw the left line
var start = particles[i-1][0][:];
var end = particles[i][0][:];
var start = lib_rope_particles[i-1][0][:];
var end = lib_rope_particles[i][0][:];
if(i == 1 && ParticleCount > 2)
if(i == 1 && lib_rope_particle_count > 2)
{
angle = Angle(particles[2][0][0], particles[2][0][1], particles[0][0][0], particles[0][0][1]);
end = particles[0][0][:];
angle = Angle(lib_rope_particles[2][0][0], lib_rope_particles[2][0][1], lib_rope_particles[0][0][0], lib_rope_particles[0][0][1]);
end = lib_rope_particles[0][0][:];
end[0] += -Sin(angle, 45*LIB_ROPE_Precision/10);
end[1] += +Cos(angle, 45*LIB_ROPE_Precision/10);
}
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][:];
angle = Angle(lib_rope_particles[2][0][0], lib_rope_particles[2][0][1], lib_rope_particles[0][0][0], lib_rope_particles[0][0][1]);
start = lib_rope_particles[0][0][:];
start[0] += -Sin(angle, 45*LIB_ROPE_Precision/10);
start[1] += +Cos(angle, 45*LIB_ROPE_Precision/10);
}
@ -200,30 +193,28 @@ func UpdateLines()
var diffangle = Vec_Angle(diff, [0,0]);
var length = Vec_Length(diff)*1000/LIB_ROPE_Precision/10;
if(i == ParticleCount-1)
if(i == lib_rope_particle_count-1)
{
var old = particles[i-2][0][:];
var old = lib_rope_particles[i-2][0][:];
var old_diff = Vec_Sub(start,old);
var o_length = Vec_Length(old_diff)*1000/LIB_ROPE_Precision/10;
if(!o_length) diff = old_diff;
else diff = Vec_Div(Vec_Mul(old_diff, length),o_length);
// objects[1][0]->Message("%d", Vec_Length(diff)*1000/Rope_Precision/10);
diffangle = Vec_Angle(diff, [0,0]);
point = Vec_Add(start, Vec_Div(diff, 2));
//length = o_length;
last_point = point;
}
if(i == 1)
{
segments[i]->SetGraphics(nil, GrappleHook);
segments[i].MeshTransformation = Trans_Mul(Trans_Translate(1500,0,0),Trans_Scale(1500));
lib_rope_segments[i]->SetGraphics(nil, GrappleHook);
lib_rope_segments[i].MeshTransformation = Trans_Mul(Trans_Translate(1500,0,0),Trans_Scale(1500));
point[0] += -Cos(diffangle, 15*LIB_ROPE_Precision/10)+Sin(diffangle, 4*LIB_ROPE_Precision);
point[1] += -Cos(diffangle, 4*LIB_ROPE_Precision)-Sin(diffangle, 15*LIB_ROPE_Precision/10);
length = 1000;
}
SetLineTransform(segments[i], -diffangle, point[0]*10-GetPartX(i)*1000,point[1]*10-GetPartY(i)*1000, length );
SetLineTransform(lib_rope_segments[i], -diffangle, point[0]*10-GetPartX(i)*1000,point[1]*10-GetPartY(i)*1000, length );
// Remember the angle
oldangle = angle;
@ -232,20 +223,20 @@ func UpdateLines()
func GetClonkAngle()
{
if(ParticleCount > 3)
return Angle(particles[-2][0][0], particles[-2][0][1], particles[-3][0][0], particles[-3][0][1]);
if(lib_rope_particle_count > 3)
return Angle(lib_rope_particles[-2][0][0], lib_rope_particles[-2][0][1], lib_rope_particles[-3][0][0], lib_rope_particles[-3][0][1]);
}
local ClonkOldSpeed;
func GetClonkPos()
{
return particles[-1][0];
return lib_rope_particles[-1][0];
}
func GetClonkOff()
{
return Vec_Sub(particles[-1][0],last_point);
return Vec_Sub(lib_rope_particles[-1][0],last_point);
}
func SetLineTransform(obj, int r, int xoff, int yoff, int length, int layer, int MirrorSegments) {
@ -262,15 +253,15 @@ func SetLineTransform(obj, int r, int xoff, int yoff, int length, int layer, int
func ForcesOnObjects()
{
if(!length) return;
if(!lib_rope_length) return;
var redo = LengthAutoTryCount();
while(length_auto && redo)
while(lib_rope_length_auto && redo)
{
var speed = Vec_Length(Vec_Sub(particles[-1][0], particles[-1][1]));
if(length == GetMaxLength())
var speed = Vec_Length(Vec_Sub(lib_rope_particles[-1][0], lib_rope_particles[-1][1]));
if(lib_rope_length == GetMaxLength())
{
if(ObjContact(objects[1][0]))
if(ObjContact(lib_rope_objects[1][0]))
speed = 40;
else speed = 100;
}
@ -283,10 +274,10 @@ func ForcesOnObjects()
if(PullObjects() )
for(var i = 0; i < 2; i++)
{
if(i == 1) j = ParticleCount-1;
var obj = objects[i][0];
if(i == 1) j = lib_rope_particle_count-1;
var obj = lib_rope_objects[i][0];
if(obj == nil || objects[i][1] == 0) continue;
if(obj == nil || lib_rope_objects[i][1] == 0) continue;
if(obj->Contained()) obj = obj->Contained();
@ -295,8 +286,8 @@ func ForcesOnObjects()
if( obj->GetAction() == "Climb")
obj->SetAction("Jump");
var xdir = BoundBy(particles[j][0][0]-particles[j][1][0], -300, 300);
var ydir = BoundBy(particles[j][0][1]-particles[j][1][1], -300, 300);
var xdir = BoundBy(lib_rope_particles[j][0][0]-lib_rope_particles[j][1][0], -300, 300);
var ydir = BoundBy(lib_rope_particles[j][0][1]-lib_rope_particles[j][1][1], -300, 300);
obj->SetXDir( xdir, LIB_ROPE_Precision);
obj->SetYDir( ydir, LIB_ROPE_Precision);

View File

@ -1,9 +1,8 @@
/**
Ropebridge
Author: Randrian
A bridge consisting of single wooden planks tied together with ropes.
@author Randrian
*/
#include Library_Rope
@ -13,50 +12,46 @@ static const Ladder_Iterations = 10;
static const Ladder_Precision = 100;
static const Ladder_SegmentLength = 5;
local particles;
local segments;
local MirrorSegments;
local ParticleCount;
public func UpdateSegmentOverlays()
{
for (var i = 1; i < GetLength(segments); i++)
for (var i = 1; i < GetLength(lib_rope_segments); i++)
{
segments[i]->CreateDouble();
segments[i]->SetGraphics("Line", GetID(), 2, 1);
segments[i]->SetGraphics("Line", GetID(), 3, 1);
segments[i].Double->SetGraphics("Line", GetID(), 4, 1);
segments[i]->SetGraphics("Line", GetID(), 5, 1);
lib_rope_segments[i]->CreateDouble();
lib_rope_segments[i]->SetGraphics("Line", GetID(), 2, 1);
lib_rope_segments[i]->SetGraphics("Line", GetID(), 3, 1);
lib_rope_segments[i].Double->SetGraphics("Line", GetID(), 4, 1);
lib_rope_segments[i]->SetGraphics("Line", GetID(), 5, 1);
if (i > 1)
{
segments[i].Double->SetGraphics("Line", GetID(), 7, 1);
segments[i]->SetGraphics("Line", GetID(), 8, 1);
lib_rope_segments[i].Double->SetGraphics("Line", GetID(), 7, 1);
lib_rope_segments[i]->SetGraphics("Line", GetID(), 8, 1);
}
segments[i]->SetSolidMask(6,0,7,3,-5,9);
if(i > 1 && i < GetLength(segments)-1)
lib_rope_segments[i]->SetSolidMask(6,0,7,3,-5,9);
if(i > 1 && i < GetLength(lib_rope_segments)-1)
{
segments[i].Plank = 1;
segments[i]->SetGraphics("Segment", GetID(), 6, 1);
segments[i]->SetClrModulation(HSL(255,0,128+Random(128)), 6);
lib_rope_segments[i].Plank = 1;
lib_rope_segments[i]->SetGraphics("Segment", GetID(), 6, 1);
lib_rope_segments[i]->SetClrModulation(HSL(255,0,128+Random(128)), 6);
}
if(i % 2 == 0)
{
var color = RGB(200,200,200);
segments[i]->SetClrModulation(color, 2);
segments[i]->SetClrModulation(color, 3);
segments[i].Double->SetClrModulation(color, 4);
segments[i]->SetClrModulation(color, 5);
segments[i].Double->SetClrModulation(color, 7);
segments[i]->SetClrModulation(color, 8);
lib_rope_segments[i]->SetClrModulation(color, 2);
lib_rope_segments[i]->SetClrModulation(color, 3);
lib_rope_segments[i].Double->SetClrModulation(color, 4);
lib_rope_segments[i]->SetClrModulation(color, 5);
lib_rope_segments[i].Double->SetClrModulation(color, 7);
lib_rope_segments[i]->SetClrModulation(color, 8);
}
}
segments[0]->CreateDouble();
segments[-1]->CreateDouble();
segments[1]->SetSolidMask();
segments[-1]->SetSolidMask();
segments[1]->SetGraphics(nil, nil,6);
lib_rope_segments[0]->CreateDouble();
lib_rope_segments[-1]->CreateDouble();
lib_rope_segments[1]->SetSolidMask();
lib_rope_segments[-1]->SetSolidMask();
lib_rope_segments[1]->SetGraphics(nil, nil,6);
return;
}
@ -76,14 +71,14 @@ public func MakeBridge(obj1, obj2)
func FxIntHangTimer()
{
TimeStep();
for(var i = 1; i < ParticleCount-1; i++)
particles[i][2] = [0,segments[i]->~GetLoadWeight()];
for(var i = 1; i < lib_rope_particle_count-1; i++)
lib_rope_particles[i][2] = [0,lib_rope_segments[i]->~GetLoadWeight()];
}
func SetFragile()
{
for(var i = 0; i < ParticleCount; i++)
segments[i].fragile = 1;
for(var i = 0; i < lib_rope_particle_count; i++)
lib_rope_segments[i].fragile = 1;
}
public func SaveScenarioObject(props)
@ -91,9 +86,9 @@ public func SaveScenarioObject(props)
if (!inherited(props, ...)) return false;
props->Remove("Category");
// Save bridge creation on scenario save
if (objects && objects[0] && objects[1])
if (lib_rope_objects && lib_rope_objects[0] && lib_rope_objects[1])
{
var o1 = objects[0][0], o2 = objects[1][0];
var o1 = lib_rope_objects[0][0], o2 = lib_rope_objects[1][0];
if (o1 && o2) props->AddCall("Bridge", this, "MakeBridge", o1, o2);
}
return true;
@ -133,9 +128,9 @@ func DrawRopeLine(start, end, i, int index)
var length = Vec_Length(diff)*1000/Ladder_Precision/8+100;
if(index != 4 && index != 7)
SetLineTransform(segments[i], -diffangle, point[0]*10-particles[i][0][0]*10,point[1]*10-particles[i][0][1]*10+2000, length, index);
else if(segments[i].Double)
SetLineTransform(segments[i].Double, -diffangle, point[0]*10-particles[i][0][0]*10,point[1]*10-particles[i][0][1]*10+2000, length, index);
SetLineTransform(lib_rope_segments[i], -diffangle, point[0]*10-lib_rope_particles[i][0][0]*10,point[1]*10-lib_rope_particles[i][0][1]*10+2000, length, index);
else if(lib_rope_segments[i].Double)
SetLineTransform(lib_rope_segments[i].Double, -diffangle, point[0]*10-lib_rope_particles[i][0][0]*10,point[1]*10-lib_rope_particles[i][0][1]*10+2000, length, index);
}
@ -145,37 +140,35 @@ func DrawRopeLine2(start, end, i, int index)
var diffangle = Vec_Angle(diff, [0,0]);
var point = Vec_Add(start, Vec_Div(diff, 2));
SetLineTransform(segments[i], -diffangle, point[0]*10-particles[i][0][0]*10,point[1]*10-particles[i][0][1]*10+2000, 1000, 6);
SetLineTransform(lib_rope_segments[i], -diffangle, point[0]*10-lib_rope_particles[i][0][0]*10,point[1]*10-lib_rope_particles[i][0][1]*10+2000, 1000, 6);
}
func UpdateLines()
{
var oldangle = Angle(particles[1][0][0], particles[1][0][1], particles[0][0][0], particles[0][0][1]);
for(var i=1; i < ParticleCount; i++)
var oldangle = Angle(lib_rope_particles[1][0][0], lib_rope_particles[1][0][1], lib_rope_particles[0][0][0], lib_rope_particles[0][0][1]);
for(var i=1; i < lib_rope_particle_count; i++)
{
// Update the Position of the Segment
segments[i]->SetPosition(particles[i][0][0], particles[i][0][1], 0, LIB_ROPE_Precision);
if(segments[i].Double)
segments[i].Double->SetPosition(particles[i][0][0], particles[i][0][1], 0, LIB_ROPE_Precision);
lib_rope_segments[i]->SetPosition(lib_rope_particles[i][0][0], lib_rope_particles[i][0][1], 0, LIB_ROPE_Precision);
if(lib_rope_segments[i].Double)
lib_rope_segments[i].Double->SetPosition(lib_rope_particles[i][0][0], lib_rope_particles[i][0][1], 0, LIB_ROPE_Precision);
// Calculate the angle to the previous segment
var angle;
angle = Angle(particles[i][0][0], particles[i][0][1], particles[i-1][0][0], particles[i-1][0][1]);
angle = Angle(lib_rope_particles[i][0][0], lib_rope_particles[i][0][1], lib_rope_particles[i-1][0][0], lib_rope_particles[i-1][0][1]);
// Every segment has not its graphics, but the graphics of the previous segment (or achor for the first)
// Otherwise the drawing order would be wrong an we would get lines over segments
// Draw the segment as an overlay for the following segment (only the last segment has two graphics (its and the previous)
/* if(i > 1 && i < GetLength(segments)-1)
SetLineTransform(segments[i], -oldangle, particles[i-1][0][0]*10-GetPartX(i)*1000,particles[i-1][0][1]*10-GetPartY(i)*1000, 1000, 6, MirrorSegments );*/
segments[i]->SetR(90+angle);
lib_rope_segments[i]->SetR(90+angle);
// Draw the left line
var start = GetRopeConnectPosition(i, 0, 0, angle, oldangle);
var end = GetRopeConnectPosition(i, 0, 1, angle, oldangle);
var end1 = start;
DrawRopeLine(start, end, i, 2);
if(segments[i].Plank)
if(lib_rope_segments[i].Plank)
DrawRopeLine2(start, end, i, 6);
// Draw the right line
@ -236,16 +229,16 @@ func GetRopeConnectPosition(int index, bool fRight, bool fEnd, int angle, int ol
var AnchorOffset = [[Ropebridge_Anchor_LeftXOffset, Ropebridge_Anchor_LeftYOffset],
[Ropebridge_Anchor_RightXOffset, Ropebridge_Anchor_RightYOffset]];
var point;
if( (fEnd == 0 && index == 1) || (fEnd == 1 && index == ParticleCount-1) )
if( (fEnd == 0 && index == 1) || (fEnd == 1 && index == lib_rope_particle_count-1) )
{
point = [objects[fEnd][0]->GetX(Ladder_Precision), objects[fEnd][0]->GetY(Ladder_Precision)];
point[0] += -Cos(objects[fEnd][0]->GetR(), AnchorOffset[fRight][0]*(-1+2*fEnd))+Sin(objects[fEnd][0]->GetR(), AnchorOffset[fRight][1]);
point[1] += -Sin(objects[fEnd][0]->GetR(), AnchorOffset[fRight][0]*(-1+2*fEnd))-Cos(objects[fEnd][0]->GetR(), AnchorOffset[fRight][1]);
point = [lib_rope_objects[fEnd][0]->GetX(Ladder_Precision), lib_rope_objects[fEnd][0]->GetY(Ladder_Precision)];
point[0] += -Cos(lib_rope_objects[fEnd][0]->GetR(), AnchorOffset[fRight][0]*(-1+2*fEnd))+Sin(lib_rope_objects[fEnd][0]->GetR(), AnchorOffset[fRight][1]);
point[1] += -Sin(lib_rope_objects[fEnd][0]->GetR(), AnchorOffset[fRight][0]*(-1+2*fEnd))-Cos(lib_rope_objects[fEnd][0]->GetR(), AnchorOffset[fRight][1]);
}
else
{
if(fEnd == 0) index -= 1;
point = particles[index][0][:];
point = lib_rope_particles[index][0][:];
point[0] += -Cos(oldangle, SegmentOffset[fRight][0]*MirrorSegments)-Sin(oldangle, SegmentOffset[fRight][1]*MirrorSegments);
point[1] += -Sin(oldangle, SegmentOffset[fRight][0]*MirrorSegments)+Cos(oldangle, SegmentOffset[fRight][1]*MirrorSegments);
}

View File

@ -1,10 +1,14 @@
/*-- Ropeladder_Grabber --*/
/**
Ropeladder Grabber
Allows for picking up the rope ladder at its base.
@author Randrian.
*/
func SaveScenarioObject() { return false; }
public func Interact(object clonk)
{
if(GetActionTarget())
if (GetActionTarget())
GetActionTarget()->StartRollUp();
else
RemoveObject();
@ -16,11 +20,16 @@ public func IsInteractable(object clonk)
return clonk->GetProcedure() == "WALK" || clonk->GetProcedure() == "SCALE" || clonk->GetProcedure() == "HANGLE";
}
func GetInteractionMetaInfo(object clonk)
public func GetInteractionMetaInfo(object clonk)
{
return { Description = "$GrabLadder$", IconName = nil, IconID = nil, Selected = false };
}
public func SaveScenarioObject() { return false; }
/*-- Properties --*/
local ActMap = {
Attach = {
Prototype = Action,
@ -29,4 +38,3 @@ local ActMap = {
},
};
local Name = "$Name$";

View File

@ -1,53 +1,56 @@
/*-- Ropeladder_Segment --*/
/**
Ropeladder Segment
@author Randrian
*/
#include Library_Ladder
local master, index;
local angle;
public func SetAngle(int new_angle) { angle = new_angle; }
public func SetAngle(int new_angle)
{
angle = new_angle;
}
public func SetMaster(new_master, new_index) { master = new_master; index = new_index; }
// Called from the ladder object to set a master and the segment index.
public func SetMaster(object new_master, int new_index)
{
master = new_master;
index = new_index;
}
public func CanNotBeClimbed(bool fClimbing)
// Returns whether the ladder can be climbed.
public func CanNotBeClimbed(bool is_climbing)
{
var test_height = 10;
if(fClimbing) test_height = 8;
if (is_climbing)
test_height = 8;
if(GBackSolid(1, test_height) && GBackSolid(-1, test_height)) return true;
if( (angle>45 && angle < 360-45) && GBackSolid(0, test_height)) return true;
if (GBackSolid(1, test_height) && GBackSolid(-1, test_height))
return true;
if (Inside(angle, 45, 315) && GBackSolid(0, test_height))
return true;
return false;
}
public func GetLadderData()
{
if(master != nil)
{
if (master)
return master->~GetLadderData(index);
}
return _inherited();
}
public func LogLadderData()
public func OnLadderGrab(object clonk)
{
var startx, starty, endx, endy;
if(master != nil)
{
master->~GetLadderData(index, startx, starty, endx, endy);
return;
}
}
public func OnLadderGrab(clonk)
{
if(master != nil)
if (master)
master->OnLadderGrab(clonk, index);
}
public func OnLadderClimb(clonk)
{
if(master != nil)
if (master)
master->OnLadderClimb(clonk, index);
}

View File

@ -1,27 +1,22 @@
/*
/**
Ropeladder
Author: Randrian
A ladder consisting of ropesegments. The physics is done completly internally with point masses.
Verlet integration and simple stick constraints are used for the rope physics. The segments are
extra objects, which handle the graphics and the detection of the ladder by the clonk.
A ladder consisting of ropesegments. The physics is done completly intern with point masses.
Verlet integration and simple stick constraints are used for the rope physics.
The segments are an extra object, which handels the graphics and the detection of the ladder by the clonk.
In a scenario you can unroll the ladder with the command Unroll(int dir, int unrolldir, int length).
Interface:
Unroll(int dir, int unrolldir, int length); // dir == -1 expand to the left, dir == 1 expand right;
// unrolldir == COMD_Down, COMD_Right, COMD_Left or COMD_Up specifies where to adjust to a wall
// length, length of segments, default 15
@author Randrian
*/
#include Library_Rope
static const Ladder_MaxParticles = 15;//30;//15*3;
static const Ladder_MaxParticles = 15;
static const Ladder_Iterations = 10;
static const Ladder_Precision = 100;
static const Ladder_SegmentLength = 5;//2;
local particles;
local segments;
local TestArray;
static const Ladder_SegmentLength = 5;
static const Ropeladder_Segment_LeftXOffset = 200;
static const Ropeladder_Segment_RightXOffset = -100;
local MaxSegmentCount;
@ -30,8 +25,6 @@ local MirrorSegments;
local UnrollDir;
local ParticleCount;
local grabber;
public func RejectUse(object clonk)
@ -72,20 +65,20 @@ public func ControlUse(object clonk, int x, int y)
public func UpdateSegmentOverlays()
{
for (var i = 1; i < GetLength(segments); i++)
for (var i = 1; i < GetLength(lib_rope_segments); i++)
{
segments[i]->SetGraphics("Line", GetID(), 2, 1);
segments[i]->SetGraphics("Line", GetID(), 3, 1);
segments[i]->SetGraphics(nil, nil, 4);
segments[i]->SetGraphics(nil, nil, 5);
lib_rope_segments[i]->SetGraphics("Line", GetID(), 2, 1);
lib_rope_segments[i]->SetGraphics("Line", GetID(), 3, 1);
lib_rope_segments[i]->SetGraphics(nil, nil, 4);
lib_rope_segments[i]->SetGraphics(nil, nil, 5);
if (i > 1)
segments[i]->SetGraphics("NoRope", segments[i]->GetID(), 4, 1);
if (i == GetLength(segments)-1)
segments[i]->SetGraphics("NoRope", segments[i]->GetID(), 5, 1);
lib_rope_segments[i]->SetGraphics("NoRope", lib_rope_segments[i]->GetID(), 4, 1);
if (i == GetLength(lib_rope_segments)-1)
lib_rope_segments[i]->SetGraphics("NoRope", lib_rope_segments[i]->GetID(), 5, 1);
if (i == 1)
{
segments[i]->SetGraphics("Anchor", GetID(), 1, 1);
segments[i]->SetGraphics("AnchorOverlay", GetID(), 5, 1);
lib_rope_segments[i]->SetGraphics("Anchor", GetID(), 1, 1);
lib_rope_segments[i]->SetGraphics("AnchorOverlay", GetID(), 5, 1);
}
}
}
@ -186,44 +179,63 @@ protected func DoUnroll(dir)
AddEffect("UnRoll", this, 1, 2, this);
}
func StartRollUp() { RemoveEffect("UnRoll", this); AddEffect("RollUp", this, 1, 1, this); }
func FxUnRollTimer()
public func StartRollUp()
{
if(ParticleCount == MaxSegmentCount)
RemoveEffect("UnRoll", this);
AddEffect("RollUp", this, 1, 1, this);
return;
}
public func FxUnRollTimer()
{
if (lib_rope_particle_count == MaxSegmentCount)
{
if(GetActTime() < MaxSegmentCount*2*2) return;
if (GetActTime() < MaxSegmentCount * 4)
return FX_OK;
// If it wasn't possible to acchieve at least half the full length we pull in again
if( -(particles[0][0][1]-particles[ParticleCount-1][0][1]) < (ParticleCount*Ladder_SegmentLength*Ladder_Precision)/2)
if( -(lib_rope_particles[0][0][1]-lib_rope_particles[lib_rope_particle_count-1][0][1]) < (lib_rope_particle_count*Ladder_SegmentLength*Ladder_Precision)/2)
StartRollUp();
return -1;
return FX_Execute_Kill;
}
AddSegment(UnrollDir*Ladder_Precision, 0);
AddSegment(UnrollDir * Ladder_Precision, 0);
return FX_OK;
}
func FxRollUpTimer() { if(ParticleCount == 0) return -1; RemoveSegment(); }
public func FxRollUpTimer()
{
if (lib_rope_particle_count == 0)
return FX_Execute_Kill;
RemoveSegment();
return FX_OK;
}
func FxIntHangTimer()
public func FxIntHangTimer()
{
// Perform a step in the rope library simulation.
TimeStep();
if(!Stuck()) TestLength();
if (!Stuck())
TestLength();
return FX_OK;
}
func TestLength()
public func TestLength()
{
if(GetActTime() < 36) return;
// If it wasn't possible to acchieve at least half the full length we pull in again
if( -(particles[0][0][1]-particles[ParticleCount-1][0][1]) < (ParticleCount*5*Ladder_Precision)/2)
if (GetActTime() < 36)
return;
// If it wasn't possible to acchieve at least half the full length we pull in again.
if (lib_rope_particles[lib_rope_particle_count - 1][0][1] - lib_rope_particles[0][0][1] < lib_rope_particle_count * 5 * Ladder_Precision / 2)
StartRollUp();
return;
}
/* --------------------- Callbacks form the rope ---------------------- */
/* To be overloaded for special segment behaviour */
/*-- Rope Callbacks --*/
// To be overloaded for special segment behaviour.
private func CreateSegment(int index, object previous)
{
var segment;
if(index == 0)
if (index == 0)
{
segment = CreateObjectAbove(Ropeladder_Segment);
segment->SetGraphics("None");
@ -232,12 +244,9 @@ private func CreateSegment(int index, object previous)
else
{
segment = CreateObjectAbove(Ropeladder_Segment);
segment->SetMaster(this, ParticleCount);
segment->SetMaster(this, lib_rope_particle_count);
segment->SetNextLadder(previous);
previous->SetPreviousLadder(segment);
segment->SetGraphics("None");
}
return segment;
@ -245,62 +254,64 @@ private func CreateSegment(int index, object previous)
private func DeleteSegment(object segment, previous)
{
if(segment)
if (segment)
segment->RemoveObject();
if(previous)
if (previous)
previous->SetPreviousLadder(nil);
return;
}
/* When the last segment is removed */
// Called when the last segment is removed.
private func RopeRemoved()
{
RemoveEffect("IntHang", this);
SetCategory(C4D_Object);
SetAction("Idle");
SetProperty("Collectible", 1);
SetProperty("Collectible", true);
// Try to move the Ropeladder somewhere out if it is stuck
// Try to move the ropeladder somewhere out if it is stuck.
TestMoveOut( 0, -1); // Up
TestMoveOut( 0, +1); // Down
TestMoveOut(-1, 0); // Left
TestMoveOut(+1, 0); // Right
// Remove the ladder grabber and reset the graphics.
grabber->RemoveObject();
SetGraphics("", GetID());
return;
}
/* --------------------- Graphics of segments ---------------------- */
func UpdateLines()
/*-- Segment Graphics --*/
public func UpdateLines()
{
var oldangle;
for(var i=1; i < ParticleCount; i++)
for (var i = 1; i < lib_rope_particle_count; i++)
{
// Update the Position of the Segment
segments[i]->SetPosition(GetPartX(i), GetPartY(i));
// Update the position of the segment.
lib_rope_segments[i]->SetPosition(GetPartX(i), GetPartY(i));
// Calculate the angle to the previous segment
// Calculate the angle to the previous segment.
var angle;
if(i >= 1)
if (i >= 1)
{
angle = Angle(particles[i][0][0], particles[i][0][1], particles[i-1][0][0], particles[i-1][0][1]);
segments[i]->SetAngle(angle);
angle = Angle(lib_rope_particles[i][0][0], lib_rope_particles[i][0][1], lib_rope_particles[i - 1][0][0], lib_rope_particles[i - 1][0][1]);
lib_rope_segments[i]->SetAngle(angle);
}
// Every segment has not its graphics, but the graphics of the previous segment (or achor for the first)
// Otherwise the drawing order would be wrong an we would get lines over segments
// Every segment does not have its own graphics, but the graphics of the previous segment (or achor for the first).
// Otherwise the drawing order would be wrong an we would get lines over segments.
// Draw the segment as an overlay for the following segment (only the last segment has two graphics (its and the previous)
if(i > 1)
SetLineTransform(segments[i], -oldangle, particles[i-1][0][0]*10-GetPartX(i)*1000,particles[i-1][0][1]*10-GetPartY(i)*1000, 1000, 4, MirrorSegments );
if(i == ParticleCount-1)
SetLineTransform(segments[i], -angle, particles[i][0][0]*10-GetPartX(i)*1000,particles[i][0][1]*10-GetPartY(i)*1000, 1000, 5, MirrorSegments );
// Draw the segment as an overlay for the following segment (only the last segment has two graphics (its and the previous).
if (i > 1)
SetLineTransform(lib_rope_segments[i], -oldangle, lib_rope_particles[i - 1][0][0] * 10-GetPartX(i) * 1000, lib_rope_particles[i - 1][0][1] * 10-GetPartY(i) * 1000, 1000, 4, MirrorSegments);
if (i == lib_rope_particle_count-1)
SetLineTransform(lib_rope_segments[i], -angle, lib_rope_particles[i][0][0] * 10 - GetPartX(i) * 1000, lib_rope_particles[i][0][1] * 10 - GetPartY(i) * 1000, 1000, 5, MirrorSegments);
// The first segment has to draw the achor too
if(i == 1)
if (i == 1)
{
SetLineTransform(segments[i], -GetR(), GetX()*1000-GetPartX(i)*1000, GetY()*1000-GetPartY(i)*1000, 1000, 1);
SetLineTransform(segments[i], -GetR(), GetX()*1000-GetPartX(i)*1000, GetY()*1000-GetPartY(i)*1000, 1000, 5);
SetLineTransform(lib_rope_segments[i], -GetR(), GetX() * 1000 - GetPartX(i) * 1000, GetY() * 1000 - GetPartY(i) * 1000, 1000, 1);
SetLineTransform(lib_rope_segments[i], -GetR(), GetX() * 1000 - GetPartX(i) * 1000, GetY() * 1000 - GetPartY(i) * 1000, 1000, 5);
}
// Draw the left line
@ -312,7 +323,7 @@ func UpdateLines()
var point = Vec_Add(start, Vec_Div(diff, 2));
var length = Vec_Length(diff)*1000/Ladder_Precision/8;
SetLineTransform(segments[i], -diffangle, point[0]*10-GetPartX(i)*1000,point[1]*10-GetPartY(i)*1000, length, 2 );
SetLineTransform(lib_rope_segments[i], -diffangle, point[0]*10-GetPartX(i)*1000,point[1]*10-GetPartY(i)*1000, length, 2 );
// Draw the right line
var start = GetRopeConnectPosition(i, 1, 0, angle, oldangle);
@ -323,15 +334,14 @@ func UpdateLines()
var point = Vec_Add(start, Vec_Div(diff, 2));
var length = Vec_Length(diff)*1000/Ladder_Precision/8;
SetLineTransform(segments[i], -diffangle, point[0]*10-GetPartX(i)*1000,point[1]*10-GetPartY(i)*1000, length, 3 );
SetLineTransform(lib_rope_segments[i], -diffangle, point[0]*10-GetPartX(i)*1000,point[1]*10-GetPartY(i)*1000, length, 3 );
// Remember the angle
oldangle = angle;
}
return;
}
static const Ropeladder_Segment_LeftXOffset = 200;
static const Ropeladder_Segment_RightXOffset = -100;
func GetRopeConnectPosition(int index, bool fRight, bool fEnd, int angle, int oldangle)
{
@ -344,7 +354,7 @@ func GetRopeConnectPosition(int index, bool fRight, bool fEnd, int angle, int ol
{
if(index >= 2)
{
start = particles[index-1][0][:];
start = lib_rope_particles[index-1][0][:];
start[0] += -Cos(oldangle, Ropeladder_Segment_LeftXOffset*MirrorSegments);
start[1] += -Sin(oldangle, Ropeladder_Segment_LeftXOffset*MirrorSegments);
}
@ -359,7 +369,7 @@ func GetRopeConnectPosition(int index, bool fRight, bool fEnd, int angle, int ol
{
if(index >= 2)
{
start = particles[index-1][0][:];
start = lib_rope_particles[index-1][0][:];
start[0] += -Cos(oldangle, Ropeladder_Segment_RightXOffset*MirrorSegments);
start[1] += -Sin(oldangle, Ropeladder_Segment_RightXOffset*MirrorSegments);
}
@ -377,13 +387,13 @@ func GetRopeConnectPosition(int index, bool fRight, bool fEnd, int angle, int ol
var end = [0,0];
if(fRight == 0)
{
end = particles[index][0][:];
end = lib_rope_particles[index][0][:];
end[0] += -Cos(angle, Ropeladder_Segment_LeftXOffset*MirrorSegments);
end[1] += -Sin(angle, Ropeladder_Segment_LeftXOffset*MirrorSegments);
}
else
{
end = particles[index][0][:];
end = lib_rope_particles[index][0][:];
end[0] += -Cos(angle, Ropeladder_Segment_RightXOffset*MirrorSegments);
end[1] += -Sin(angle, Ropeladder_Segment_RightXOffset*MirrorSegments);
}
@ -391,75 +401,89 @@ func GetRopeConnectPosition(int index, bool fRight, bool fEnd, int angle, int ol
}
}
func SetLineTransform(obj, int r, int xoff, int yoff, int length, int layer, int MirrorSegments) {
if(!MirrorSegments) MirrorSegments = 1;
var fsin=Sin(r, 1000), fcos=Cos(r, 1000);
// set matrix values
public func SetLineTransform(obj, int r, int xoff, int yoff, int length, int layer, int MirrorSegments)
{
if (!MirrorSegments)
MirrorSegments = 1;
var fsin = Sin(r, 1000), fcos=Cos(r, 1000);
// Draw transform the object.
obj->SetObjDrawTransform (
+fcos*MirrorSegments, +fsin*length/1000, xoff,
-fsin*MirrorSegments, +fcos*length/1000, yoff,layer
-fsin*MirrorSegments, +fcos*length/1000, yoff, layer
);
return;
}
/* --------------------- Clonk on ladder ---------------------- */
public func OnLadderGrab(clonk, index)
/*-- Clonk Interaction --*/
// Perturb some segments when the clonk jumps onto the ladder
public func OnLadderGrab(object clonk, int index)
{
// Do some speed when the clonk jumps on the ladder
if(index == 0) return;
particles[index][0][0] += BoundBy(clonk->GetXDir()/2, -25, 25)*Ladder_Precision;
if (index == 0)
return;
lib_rope_particles[index][0][0] += BoundBy(clonk->GetXDir() / 2, -25, 25) * Ladder_Precision;
return;
}
public func OnLadderClimb(clonk, index)
// Called when the clonk climbs the ladder.
public func OnLadderClimb(object clonk, int index)
{
var dir = 2 * clonk->GetDir() - 1;
// The clonk drags on the upper segments and pushes on the lower ones
if(index > 2 && index < ParticleCount-3)
if (index > 2 && index < lib_rope_particle_count - 3)
{
particles[index-2][0][0] -= 1*Ladder_Precision/5*(-1+2*clonk->GetDir());
particles[index+2][0][0] += 1*Ladder_Precision/5*(-1+2*clonk->GetDir());
lib_rope_particles[index-2][0][0] -= dir * Ladder_Precision / 5;
lib_rope_particles[index+2][0][0] += dir * Ladder_Precision / 5;
}
else if(index > 2 && index < ParticleCount-2)
else if(index > 2 && index < lib_rope_particle_count - 2)
{
particles[index-2][0][0] -= 1*Ladder_Precision/5*(-1+2*clonk->GetDir());
particles[index+1][0][0] += 1*Ladder_Precision/5*(-1+2*clonk->GetDir());
lib_rope_particles[index-2][0][0] -= dir * Ladder_Precision / 5;
lib_rope_particles[index+1][0][0] += dir * Ladder_Precision / 5;
}
return;
}
public func GetLadderData(index)
public func GetLadderData(int index)
{
var startx = particles[index][0][0]*10;
var starty = particles[index][0][1]*10;
if(index == 0)
var startx = lib_rope_particles[index][0][0] * 10;
var starty = lib_rope_particles[index][0][1] * 10;
if (index == 0)
{
var angle = Angle(particles[2][0][0], particles[2][0][1], particles[0][0][0], particles[0][0][1]);
return [startx, starty, startx, starty-5000, angle];
var angle = Angle(lib_rope_particles[2][0][0], lib_rope_particles[2][0][1], lib_rope_particles[0][0][0], lib_rope_particles[0][0][1]);
return [startx, starty, startx, starty - 5000, angle];
}
if(index == ParticleCount-1 || segments[index+1]->~CanNotBeClimbed())
if (index == lib_rope_particle_count-1 || lib_rope_segments[index + 1]->~CanNotBeClimbed())
{
angle = Angle(particles[index][0][0], particles[index][0][1], particles[index-2][0][0], particles[index-2][0][1]);
angle = Angle(lib_rope_particles[index][0][0], lib_rope_particles[index][0][1], lib_rope_particles[index-2][0][0], lib_rope_particles[index-2][0][1]);
}
else
angle = Angle(particles[index+1][0][0], particles[index+1][0][1], particles[index-1][0][0], particles[index-1][0][1]);
var endx = particles[index-1][0][0]*10;
var endy = particles[index-1][0][1]*10;
angle = Angle(lib_rope_particles[index + 1][0][0], lib_rope_particles[index + 1][0][1], lib_rope_particles[index - 1][0][0], lib_rope_particles[index - 1][0][1]);
var endx = lib_rope_particles[index - 1][0][0] * 10;
var endy = lib_rope_particles[index - 1][0][1] * 10;
return [startx, starty, endx, endy, angle];
}
func Hit()
public func Hit()
{
Sound("WoodHit?");
}
// Save unrolled ladders in scenario
// Save unrolled ladders in scenario.
public func SaveScenarioObject(props)
{
if (!inherited(props, ...)) return false;
if (UnrollDir) props->AddCall("Unroll", this, "Unroll", UnrollDir);
if (!inherited(props, ...))
return false;
if (UnrollDir)
props->AddCall("Unroll", this, "Unroll", UnrollDir);
return true;
}
public func IsTool() { return true; }
public func IsToolProduct() { return true; }
/*-- Properties --*/
local ActMap = {
Hanging = {
Prototype = Action,

View File

@ -174,7 +174,7 @@ public func LadderStep(target, effect, fUp)
return false;
}
}
if (effect.ladder == nil) return 0;
if (effect.ladder == nil) return false;
return true;
}
@ -182,7 +182,7 @@ public func FxIntClimbControlTimer(object target, proplist effect, int time)
{
if (GetAction() != "Climb" || Contained())
return FX_Execute_Kill;
if (effect.ladder && effect.ladder->~CanNotBeClimbed(1))
if (effect.ladder && effect.ladder->~CanNotBeClimbed(true))
effect.ladder = nil;
if (!effect.ladder)
{
@ -200,7 +200,7 @@ public func FxIntClimbControlTimer(object target, proplist effect, int time)
if (GetComDir() == COMD_Up)
step = 1;
if (step && LadderStep(target, effect, step) == 0)
if (step && !LadderStep(target, effect, step))
{
var contact = GetContact(-1);
if (contact & CNAT_Left || contact & CNAT_Right)

View File

@ -1,44 +1,47 @@
/*--
Ladder control
Authors: Randrian
/**
Ladder Control
Containes the basic functionality for ladders.
--*/
@author Randrian
*/
local next_segment;
local prev_segment;
public func IsLadder() { return true; }
// Returns the segment (start position, end position) on which the clonk can climb.
// Returns the segment (start x, start y, end x, end y, angle) on which the clonk can climb.
public func GetLadderData()
{
// Normally (if not overloaded) interpret the first vertex as start and the second as end
// Normally (if not overloaded) interpret the first vertex as start and the second as end.
return [
GetX() + GetVertex(0, 0),
GetY() + GetVertex(0, 1),
GetX() + GetVertex(1, 0),
GetY() + GetVertex(1, 1),
0];
0
];
}
// Get the connected segments
// Get the connected previous segment.
public func GetPreviousLadder()
{
return prev_segment;
}
// Get the connected next segment.
public func GetNextLadder()
{
return next_segment;
}
// Set the connected segments
// Set the connected previous segment.
public func SetPreviousLadder(object ladder)
{
prev_segment = ladder;
}
// Set the connected next segment.
public func SetNextLadder(object ladder)
{
next_segment = ladder;

View File

@ -1,25 +1,30 @@
/**
Rope Library
This library contains all functions for using dynamic ropes
This library contains all functions for using dynamic ropes.
@author Randrian
*/
// Some constants for the method.
static const LIB_ROPE_Iterations = 10;
static const LIB_ROPE_Precision = 100;
static const LIB_ROPE_SegmentLength = 5;
static const LIB_ROPE_LandscapeMoveDirs = [[0, 1], [1, 0], [1, 1], [0, 2], [1, 2], [2, 0], [2, 1], [2, 2], [0, 3], [1, 3], [2, 3], [3, 0], [3, 1], [3, 2], [0, 4],
[1, 4], [2, 4], [3, 3], [4, 0], [4, 1], [4, 2], [0, 5], [1, 5], [2, 5], [3, 4], [3, 5], [4, 3], [4, 4], [5, 0], [5, 1],
[5, 2], [5, 3], [0, 6], [1, 6], [2, 6], [3, 6], [4, 5], [5, 4], [6, 0], [6, 1], [6, 2], [6, 3], [0, 7], [1, 7], [2, 7],
[3, 7], [4, 6], [5, 5], [5, 6], [6, 4], [6, 5], [7, 0], [7, 1], [7, 2], [7, 3], [0, 8], [1, 8], [2, 8], [3, 8], [4, 7],
[4, 8], [5, 7], [6, 6], [7, 4], [7, 5], [8, 0], [8, 1], [8, 2], [8, 3], [8, 4], [0, 9], [1, 9], [2, 9], [3, 9], [4, 9],
[5, 8], [6, 7], [7, 6], [7, 7], [8, 5], [9, 0], [9, 1], [9, 2], [9, 3], [9, 4]
];
local particles;
local segments;
local TestArray;
local ParticleCount;
local objects;
local length;
local length_auto;
local Max_Length;
// Internal variable of this library.
local lib_rope_length; // Length of the rope.
local lib_rope_particle_count; // Number of rope particles.
local lib_rope_particles; // List of rope particles.
local lib_rope_segments; // List of rope segments.
local lib_rope_objects; // List of rope objects.
local lib_rope_length_auto; // Automatic rope length (true/false).
local lib_rope_max_length; // Maximum rope length.
public func GetRopeGravity()
{
@ -33,16 +38,16 @@ public func GetRopeGravity()
*/
protected func StartRope()
{
objects = [[this, 0], [nil, nil]];
TestArray = [[0, 1], [1, 0], [1, 1], [0, 2], [1, 2], [2, 0], [2, 1], [2, 2], [0, 3], [1, 3], [2, 3], [3, 0], [3, 1], [3, 2], [0, 4], [1, 4], [2, 4], [3, 3], [4, 0], [4, 1], [4, 2], [0, 5], [1, 5], [2, 5], [3, 4], [3, 5], [4, 3], [4, 4], [5, 0], [5, 1], [5, 2], [5, 3], [0, 6], [1, 6], [2, 6], [3, 6], [4, 5], [5, 4], [6, 0], [6, 1], [6, 2], [6, 3], [0, 7], [1, 7], [2, 7], [3, 7], [4, 6], [5, 5], [5, 6], [6, 4], [6, 5], [7, 0], [7, 1], [7, 2], [7, 3], [0, 8], [1, 8], [2, 8], [3, 8], [4, 7], [4, 8], [5, 7], [6, 6], [7, 4], [7, 5], [8, 0], [8, 1], [8, 2], [8, 3], [8, 4], [0, 9], [1, 9], [2, 9], [3, 9], [4, 9], [5, 8], [6, 7], [7, 6], [7, 7], [8, 5], [9, 0], [9, 1], [9, 2], [9, 3], [9, 4]];
length = LIB_ROPE_SegmentLength;
lib_rope_objects = [[this, 0], [nil, nil]];
lib_rope_length = LIB_ROPE_SegmentLength;
ParticleCount = 1;
segments = CreateArray(ParticleCount);
segments[0] = CreateSegment(0, nil);
lib_rope_particle_count = 1;
lib_rope_segments = [];
lib_rope_segments[0] = CreateSegment(0, nil);
particles = CreateArray(ParticleCount);
particles[0] = [[ GetX()*LIB_ROPE_Precision, GetY()*LIB_ROPE_Precision], [(GetX()+1)*LIB_ROPE_Precision, GetY()*LIB_ROPE_Precision], [0,GetRopeGravity()], 0];
lib_rope_particles = [];
lib_rope_particles[0] = [[GetX() * LIB_ROPE_Precision, GetY() * LIB_ROPE_Precision], [(GetX() + 1) * LIB_ROPE_Precision, GetY() * LIB_ROPE_Precision], [0, GetRopeGravity()], 0];
return;
}
/** Connects \a obj1 and \a obj2
@ -53,43 +58,40 @@ protected func StartRope()
*/
public func StartRopeConnect(object obj1, object obj2)
{
length = ObjectDistance(obj1, obj2);
objects = [[obj1, 0], [obj2, 1]];
TestArray = [[0, 1], [1, 0], [1, 1], [0, 2], [1, 2], [2, 0], [2, 1], [2, 2], [0, 3], [1, 3], [2, 3], [3, 0], [3, 1], [3, 2], [0, 4], [1, 4], [2, 4], [3, 3], [4, 0], [4, 1], [4, 2], [0, 5], [1, 5], [2, 5], [3, 4], [3, 5], [4, 3], [4, 4], [5, 0], [5, 1], [5, 2], [5, 3], [0, 6], [1, 6], [2, 6], [3, 6], [4, 5], [5, 4], [6, 0], [6, 1], [6, 2], [6, 3], [0, 7], [1, 7], [2, 7], [3, 7], [4, 6], [5, 5], [5, 6], [6, 4], [6, 5], [7, 0], [7, 1], [7, 2], [7, 3], [0, 8], [1, 8], [2, 8], [3, 8], [4, 7], [4, 8], [5, 7], [6, 6], [7, 4], [7, 5], [8, 0], [8, 1], [8, 2], [8, 3], [8, 4], [0, 9], [1, 9], [2, 9], [3, 9], [4, 9], [5, 8], [6, 7], [7, 6], [7, 7], [8, 5], [9, 0], [9, 1], [9, 2], [9, 3], [9, 4]];
ParticleCount = length/LIB_ROPE_SegmentLength;
lib_rope_length = ObjectDistance(obj1, obj2);
lib_rope_objects = [[obj1, 0], [obj2, 1]];
lib_rope_particle_count = lib_rope_length/LIB_ROPE_SegmentLength;
var yoff = 0;
if(ParticleCount < 2)
if(lib_rope_particle_count < 2)
{
ParticleCount = 2;
lib_rope_particle_count = 2;
yoff = 1;
length = 10;
lib_rope_length = 10;
}
segments = CreateArray(ParticleCount);
for(var i = 0; i < ParticleCount; i++)
lib_rope_segments = [];
for(var i = 0; i < lib_rope_particle_count; i++)
{
var prev = nil;
if(i > 0) prev = segments[i-1];
segments[i] = CreateSegment(i, prev);
if(i > 0) prev = lib_rope_segments[i-1];
lib_rope_segments[i] = CreateSegment(i, prev);
}
particles = CreateArray(ParticleCount);
lib_rope_particles = [];
var x, y;
for(var i = 0; i < ParticleCount; i++)
for(var i = 0; i < lib_rope_particle_count; i++)
{
x = obj1->GetX(LIB_ROPE_Precision)*(ParticleCount-i)/ParticleCount+obj2->GetX(LIB_ROPE_Precision)*i/ParticleCount;
y = obj1->GetY(LIB_ROPE_Precision)*(ParticleCount-i)/ParticleCount+obj2->GetY(LIB_ROPE_Precision)*i/ParticleCount;
x = obj1->GetX(LIB_ROPE_Precision)*(lib_rope_particle_count-i)/lib_rope_particle_count+obj2->GetX(LIB_ROPE_Precision)*i/lib_rope_particle_count;
y = obj1->GetY(LIB_ROPE_Precision)*(lib_rope_particle_count-i)/lib_rope_particle_count+obj2->GetY(LIB_ROPE_Precision)*i/lib_rope_particle_count;
y += yoff*i;
// Pos, Oldpos, acceleration (gravity), mass.
particles[i] = [[ x, y], [ x, y], [0,GetRopeGravity()], 1];
lib_rope_particles[i] = [[ x, y], [ x, y], [0,GetRopeGravity()], 1];
}
particles[0][2] = [0,0];
particles[0][3] = 0;
particles[-1][2] = [0,0];
particles[-1][3] = 1;
lib_rope_particles[0][2] = [0,0];
lib_rope_particles[0][3] = 0;
lib_rope_particles[-1][2] = [0,0];
lib_rope_particles[-1][3] = 1;
ConnectLoose();
@ -106,12 +108,12 @@ protected func Destruction()
public func SetMaxLength(int newlength)
{
Max_Length = newlength;
lib_rope_max_length = newlength;
}
public func GetMaxLength()
{
return Max_Length;
return lib_rope_max_length;
}
/** Removes the rope
@ -119,9 +121,9 @@ public func GetMaxLength()
*/
public func RemoveRope()
{
if(segments)
for(var segment in segments)
DeleteSegment(segment);
if (lib_rope_segments)
for (var segment in lib_rope_segments)
DeleteSegment(segment);
}
/** Sets the fixed status of the two targets
@ -132,35 +134,31 @@ public func RemoveRope()
*/
public func SetFixed(bool fixed_1, bool fixed_2)
{
objects[0][1] = !fixed_1;
objects[1][1] = !fixed_2;
particles[ 0][3] = objects[0][1];
particles[-1][3] = objects[1][1];
lib_rope_objects[0][1] = !fixed_1;
lib_rope_objects[1][1] = !fixed_2;
lib_rope_particles[ 0][3] = lib_rope_objects[0][1];
lib_rope_particles[-1][3] = lib_rope_objects[1][1];
}
/** Sets the rope connection mode to \a loose
* A loose rope will vary the length according to the connected objects. If a object is non-fixed and pulls at the rope the length will increase.
* If it doesn't pull the length will decrease.
*/
// Sets the rope connection mode to loose. A loose rope will vary the length according to the connected objects.
// If a object is non-fixed and pulls at the rope the length will increase. If it doesn't pull the length will decrease.
public func ConnectLoose()
{
length_auto = 1;
lib_rope_length_auto = true;
}
/** Sets the rope connection mode to \a pull
* The rope tries to keep its length and pull at non-fixed objects.
*/
local table2 ;//= [80,126,177,232,292,355,421,491,563,638,716,796,878,963,1050,1139,1230,1323,1417,1514,1612,1712,1814,1917,2022,2128,2236,2346,2457,2569,2683,2798,2914,3032,3151,3271,3393,3516,3640,3765,3891,4019,4148,4278,4409,4541,4674,4808,4943,5080,5217,5356,5495,5635,5777,5919,6063,6207,6352,6498,6645,6794,6943,7092,7243,7395,7547,7701,7855,8010,8166,8323,8481,8639,8798,8958,9119,9281,9444,9607,9771,9936,10102,10268,10435,10603,10772,10941,11111,11282,11454,11626,11799,11973,12148,12323,12499,12675,12853,13031,13209,13389,13569,13749,13931,14113,14295,14479,14663,14847,15033,15219,15405,15593,15780,15969,16158,16348,16538,16729,16921,17113,17306,17499,17693,17888,18083,18279,18475,18672,18870,19068,19267,19466,19666,19867,20000,20000,20000,2000];
// Sets the rope connection mode to pull. The rope tries to keep its length and pull at non-fixed objects.
public func ConnectPull()
{
length_auto = 0;
lib_rope_length_auto = false;
}
public func TogglePull()
{
if(length_auto) ConnectPull();
else ConnectLoose();
if (lib_rope_length_auto)
ConnectPull();
else
ConnectLoose();
}
/** Create a new segment
@ -178,7 +176,7 @@ private func CreateSegment(int index, object previous) { }
*/
private func DeleteSegment(object segment, previous)
{
if(segment)
if (segment)
segment->RemoveObject();
}
@ -194,65 +192,60 @@ private func RopeRemoved() { }
/* Adding and removing segments */
public func AddSegment(int xoffset, int yoffset)
{
segments[ParticleCount] = CreateSegment(ParticleCount, segments[ParticleCount-1]);
lib_rope_segments[lib_rope_particle_count] = CreateSegment(lib_rope_particle_count, lib_rope_segments[lib_rope_particle_count - 1]);
var oldx = particles[ParticleCount-1][0][0];
var oldy = particles[ParticleCount-1][0][1];
particles[ParticleCount] = [[ oldx+xoffset, oldy+yoffset], [ oldx, oldy], [0,GetRopeGravity()], 1]; // Pos, Oldpos, acceleration (gravity), mass
var oldx = lib_rope_particles[lib_rope_particle_count - 1][0][0];
var oldy = lib_rope_particles[lib_rope_particle_count - 1][0][1];
// Pos, Oldpos, acceleration (gravity), mass
lib_rope_particles[lib_rope_particle_count] = [[oldx + xoffset, oldy + yoffset], [oldx, oldy], [0, GetRopeGravity()], 1];
lib_rope_particle_count++;
ParticleCount++;
lib_rope_length += LIB_ROPE_SegmentLength;
length += LIB_ROPE_SegmentLength;
UpdateSegmentOverlays();
return;
}
// Removes a segment from the middle of the rope.
public func PickSegment(int index)
{
if(index >= lib_rope_particle_count-1) return RemoveSegment();
var previous = nil;
if(index > 0) previous = lib_rope_segments[index-1];
DeleteSegment(lib_rope_segments[index], previous);
for(var i = index; i < lib_rope_particle_count-1; i++)
{
lib_rope_segments[i] = lib_rope_segments[i+1];
lib_rope_particles[i] = lib_rope_particles[i+1];
}
lib_rope_particle_count--;
SetLength(lib_rope_segments, lib_rope_particle_count);
SetLength(lib_rope_particles, lib_rope_particle_count);
UpdateSegmentOverlays();
}
/** Removes a segment from the middle of the rope
* @param index index of the segment to be removed
*/
public func PickSegment(int index) // Removes a segment form the middle
// Removes a segment from the end of the rope, set no_length_adjust to not adjust rope length.
public func RemoveSegment(bool no_length_adjust)
{
if(index >= ParticleCount-1) return RemoveSegment();
lib_rope_particle_count--;
var previous = nil;
if(index > 0) previous = segments[index-1];
DeleteSegment(segments[index], previous);
if (lib_rope_particle_count-1 >= 0)
previous = lib_rope_segments[lib_rope_particle_count - 1];
DeleteSegment(lib_rope_segments[lib_rope_particle_count], previous);
for(var i = index; i < ParticleCount-1; i++)
{
segments[i] = segments[i+1];
particles[i] = particles[i+1];
}
ParticleCount--;
if (lib_rope_particle_count == 0)
return RopeRemoved();
SetLength(segments, ParticleCount);
SetLength(particles, ParticleCount);
UpdateSegmentOverlays();
}
/** Removes a segment from the end of the rope
* @param fNoLengthAdjust wether the length of the rope shall be decreased accordingly
*/
public func RemoveSegment(fNoLengthAdjust)
{
ParticleCount--;
var previous = nil;
if(ParticleCount-1 >= 0) previous = segments[ParticleCount-1];
DeleteSegment(segments[ParticleCount], previous);
if(ParticleCount == 0)
{
RopeRemoved();
return;
}
if(!fNoLengthAdjust)
length -= LIB_ROPE_SegmentLength;
SetLength(segments, ParticleCount);
SetLength(particles, ParticleCount);
if (!no_length_adjust)
lib_rope_length -= LIB_ROPE_SegmentLength;
SetLength(lib_rope_segments, lib_rope_particle_count);
SetLength(lib_rope_particles, lib_rope_particle_count);
UpdateSegmentOverlays();
return;
}
/** Callback, when the maximal length of the rope is reached
@ -265,20 +258,20 @@ public func MaxLengthReached() { }
*/
public func DoLength(int dolength)
{
length += dolength;
lib_rope_length += dolength;
if(GetMaxLength())
if(length >= GetMaxLength())
if(lib_rope_length >= GetMaxLength())
{
MaxLengthReached();
length = GetMaxLength();
lib_rope_length = GetMaxLength();
}
if(length < LIB_ROPE_SegmentLength*2) length = LIB_ROPE_SegmentLength*2;
if(lib_rope_length < LIB_ROPE_SegmentLength*2) lib_rope_length = LIB_ROPE_SegmentLength*2;
var last_length = GetLastLength();
// Remove Points
while( last_length < LIB_ROPE_SegmentLength*LIB_ROPE_Precision/2 && ParticleCount > 2)
while( last_length < LIB_ROPE_SegmentLength*LIB_ROPE_Precision/2 && lib_rope_particle_count > 2)
{
particles[ParticleCount-2] = particles[ParticleCount-1];
lib_rope_particles[lib_rope_particle_count-2] = lib_rope_particles[lib_rope_particle_count-1];
RemoveSegment(1);
last_length = GetLastLength();
@ -286,39 +279,38 @@ public func DoLength(int dolength)
var i = 0;
while( last_length > LIB_ROPE_SegmentLength*LIB_ROPE_Precision*3/2)
{
ParticleCount++;
SetLength(particles, ParticleCount);
var x2 = particles[ParticleCount-2][0][0];
var y2 = particles[ParticleCount-2][0][1];
lib_rope_particle_count++;
SetLength(lib_rope_particles, lib_rope_particle_count);
var x2 = lib_rope_particles[lib_rope_particle_count-2][0][0];
var y2 = lib_rope_particles[lib_rope_particle_count-2][0][1];
var x4 = particles[ParticleCount-2][1][0];
var y4 = particles[ParticleCount-2][1][1];
// particles[-1] = [[0,0], [0,0], [0,0], 0];
particles[-1] = [[x2, y2], [x4, y4], [0,GetRopeGravity()], 1];
var x4 = lib_rope_particles[lib_rope_particle_count-2][1][0];
var y4 = lib_rope_particles[lib_rope_particle_count-2][1][1];
lib_rope_particles[-1] = [[x2, y2], [x4, y4], [0,GetRopeGravity()], 1];
for(var i = ParticleCount-2; i > 0; i--)
for(var i = lib_rope_particle_count-2; i > 0; i--)
{
var x = particles[i-1][0][0];
var y = particles[i-1][0][1];
var x2 = particles[i][0][0];
var y2 = particles[i][0][1];
var x = lib_rope_particles[i-1][0][0];
var y = lib_rope_particles[i-1][0][1];
var x2 = lib_rope_particles[i][0][0];
var y2 = lib_rope_particles[i][0][1];
var x3 = particles[i-1][1][0];
var y3 = particles[i-1][1][1];
var x4 = particles[i][1][0];
var y4 = particles[i][1][1];
var x3 = lib_rope_particles[i-1][1][0];
var y3 = lib_rope_particles[i-1][1][1];
var x4 = lib_rope_particles[i][1][0];
var y4 = lib_rope_particles[i][1][1];
particles[i] = [[ x/ParticleCount +x2*(ParticleCount-1)/ParticleCount, y/ParticleCount +y2*(ParticleCount-1)/ParticleCount],
[ x3/ParticleCount+x4*(ParticleCount-1)/ParticleCount, y3/ParticleCount+y4*(ParticleCount-1)/ParticleCount], [0,1*LIB_ROPE_Precision], 1];
lib_rope_particles[i] = [[ x/lib_rope_particle_count +x2*(lib_rope_particle_count-1)/lib_rope_particle_count, y/lib_rope_particle_count +y2*(lib_rope_particle_count-1)/lib_rope_particle_count],
[ x3/lib_rope_particle_count+x4*(lib_rope_particle_count-1)/lib_rope_particle_count, y3/lib_rope_particle_count+y4*(lib_rope_particle_count-1)/lib_rope_particle_count], [0,1*LIB_ROPE_Precision], 1];
}
SetLength(segments, ParticleCount);
segments[ParticleCount-1] = CreateSegment(ParticleCount, segments[ParticleCount-2]);
SetLength(lib_rope_segments, lib_rope_particle_count);
lib_rope_segments[lib_rope_particle_count-1] = CreateSegment(lib_rope_particle_count, lib_rope_segments[lib_rope_particle_count-2]);
last_length = GetLastLength();
}
UpdateLines();
particles[ 0][3] = objects[0][1];
particles[-1][3] = objects[1][1];
lib_rope_particles[ 0][3] = lib_rope_objects[0][1];
lib_rope_particles[-1][3] = lib_rope_objects[1][1];
return;
}
@ -327,7 +319,7 @@ public func DoLength(int dolength)
*/
public func GetLastLength()
{
return length*LIB_ROPE_Precision-LIB_ROPE_SegmentLength*LIB_ROPE_Precision*(ParticleCount-1);
return lib_rope_length*LIB_ROPE_Precision-LIB_ROPE_SegmentLength*LIB_ROPE_Precision*(lib_rope_particle_count-1);
}
/** This is called when a new segment is added, the segments can adjust their appeareance to that
@ -348,6 +340,7 @@ public func TimeStep()
SatisfyConstraints();
ForcesOnObjects();
UpdateLines();
return;
}
/** Summs all the fores on the segments
@ -356,17 +349,18 @@ public func TimeStep()
*/
public func AccumulateForces()
{
for(var i = 1; i < ParticleCount; i++)
for (var i = 1; i < lib_rope_particle_count; i++)
{
var fx = 0, fy = 0, angle;
if(i < ParticleCount-2)
if (i < lib_rope_particle_count - 2)
{
angle = Angle(particles[i][0][0], particles[i][0][1], particles[i+1][0][0], particles[i+1][0][1]);
fx = Sin(angle, 5*LIB_ROPE_Precision);
fy =-Cos(angle, 5*LIB_ROPE_Precision);
angle = Angle(lib_rope_particles[i][0][0], lib_rope_particles[i][0][1], lib_rope_particles[i + 1][0][0], lib_rope_particles[i + 1][0][1]);
fx = Sin(angle, 5 * LIB_ROPE_Precision);
fy = -Cos(angle, 5 * LIB_ROPE_Precision);
}
particles[i][2] = [fx,fy+GetRopeGravity()];
lib_rope_particles[i][2] = [fx, fy + GetRopeGravity()];
}
return;
}
/** Verlet integration step
@ -381,26 +375,22 @@ private func Verlet()
// Verlet
var start = 1;
var last = ParticleCount;
if(objects[-1][1] == 1 && PullObjects()) last -= 1;
for(var i = start; i < ParticleCount; i++)
var last = lib_rope_particle_count;
if(lib_rope_objects[-1][1] == 1 && PullObjects()) last -= 1;
for(var i = start; i < lib_rope_particle_count; i++)
{
if(i == ParticleCount-1)
{
//particles[i][0] = particles[i][1][:];
//continue;
}
var x = particles[i][0][:];
var x = lib_rope_particles[i][0][:];
var temp = x;
var oldx = particles[i][1][:];
var a = particles[i][2][:];
var oldx = lib_rope_particles[i][1][:];
var a = lib_rope_particles[i][2][:];
// Verlet step, get speed out of distance moved relativ to the last position
particles[i][0][0] += x[0]-oldx[0]+a[0];
particles[i][0][1] += x[1]-oldx[1]+a[1];
particles[i][1] = temp;
particles[i][4] = 0;
lib_rope_particles[i][0][0] += x[0]-oldx[0]+a[0];
lib_rope_particles[i][0][1] += x[1]-oldx[1]+a[1];
lib_rope_particles[i][1] = temp;
lib_rope_particles[i][4] = 0;
}
return;
}
/** Moves a particle to the position of the object
@ -409,103 +399,103 @@ private func Verlet()
*/
public func SetParticleToObject(int index, int obj_index)
{
var obj = objects[obj_index][0];
if(obj == nil) return;
var obj = lib_rope_objects[obj_index][0];
if (!obj)
return;
if(obj->Contained()) obj = obj->Contained();
particles[index][0][0] = obj->GetX(LIB_ROPE_Precision);
particles[index][0][1] = obj->GetY(LIB_ROPE_Precision);
if (obj->Contained())
obj = obj->Contained();
lib_rope_particles[index][0][0] = obj->GetX(LIB_ROPE_Precision);
lib_rope_particles[index][0][1] = obj->GetY(LIB_ROPE_Precision);
return;
//Log("Set %d %d", index, obj_index);
// particles[index][1][0] = particles[index][0][0];
// particles[index][1][1] = particles[index][0][1];
}
public func ConstraintObjects()
{
if(length_auto && length < GetMaxLength())
{
// Copy Position of the objects
for(var i = 0, i2 = 0; i < 2; i++ || i2--)
SetParticleToObject(i2, i);
}
if (lib_rope_length_auto && lib_rope_length < GetMaxLength())
{
// Copy position of the objects.
for (var i = 0, i2 = 0; i < 2; i++ || i2--)
SetParticleToObject(i2, i);
}
return;
}
public func ConstraintLength()
{
// Satisfy all stick constraints (move the particles to fit the length)
var normal_restlength = LIB_ROPE_SegmentLength*LIB_ROPE_Precision;
var restlength;
var invmass1, invmass2;
var delta = [0,0], deltaDot, deltalength; // diff
for(var i=0; i < ParticleCount-1; i++)
// Satisfy all stick constraints (move the particles to fit the length).
var normal_restlength = LIB_ROPE_SegmentLength * LIB_ROPE_Precision;
var restlength, invmass1, invmass2, delta1, delta2, delta_length;
for (var i = 0; i < lib_rope_particle_count - 1; i++)
{
// Keep length
restlength = normal_restlength; // normal length between two points
if(i == ParticleCount-2)
// Keep length, normal length between two points.
restlength = normal_restlength;
if (i == lib_rope_particle_count - 2)
restlength = GetLastLength();
// Get coordinates and inverse masses
invmass1 = particles[i][3];
invmass2 = particles[i+1][3];
// calculate difference
delta[0] = particles[i+1][0][0]-particles[i][0][0];
delta[1] = particles[i+1][0][1]-particles[i][0][1];
deltaDot = delta[0]*delta[0]+delta[1]*delta[1];
deltalength = Sqrt(delta[0]*delta[0]+delta[1]*delta[1]);
if(deltalength < restlength)
// Get coordinates and inverse masses.
invmass1 = lib_rope_particles[i ][3];
invmass2 = lib_rope_particles[i + 1][3];
// Calculate difference.
delta1 = lib_rope_particles[i + 1][0][0] - lib_rope_particles[i][0][0];
delta2 = lib_rope_particles[i + 1][0][1] - lib_rope_particles[i][0][1];
delta_length = Sqrt(delta1**2 + delta2**2);
if (delta_length < restlength)
continue;
delta[0] = delta[0]*(deltalength-restlength)/(deltalength*(invmass1+invmass2));
delta[1] = delta[1]*(deltalength-restlength)/(deltalength*(invmass1+invmass2));
// Set new positions
particles[i ][0][0] += delta[0]*invmass1;//*invmass1;//*diff/1000;
particles[i ][0][1] += delta[1]*invmass1;//*invmass1;//*diff/1000;
particles[i+1][0][0] -= delta[0]*invmass2;//*invmass2;//*diff/1000;
particles[i+1][0][1] -= delta[1]*invmass2;//*invmass2;//*diff/1000;
delta1 = delta1 * (delta_length - restlength) / (delta_length * (invmass1 + invmass2));
delta2 = delta2 * (delta_length - restlength) / (delta_length * (invmass1 + invmass2));
// Set new positions.
lib_rope_particles[i ][0][0] += delta1*invmass1;
lib_rope_particles[i ][0][1] += delta2*invmass1;
lib_rope_particles[i + 1][0][0] -= delta1*invmass2;
lib_rope_particles[i + 1][0][1] -= delta2*invmass2;
}
return;
}
public func ConstraintLandscape()
{
for(var i=0; i < ParticleCount; i++)
for (var i = 0; i < lib_rope_particle_count; i++)
{
// Don't touch ground.
if (GBackSolid(GetPartX(i) - GetX(), GetPartY(i) - GetY()))
{
// Don't touch ground
if(GBackSolid(GetPartX(i)-GetX(), GetPartY(i)-GetY()) )
// Moving left?
var xdir = -1;
if (lib_rope_particles[i][0][0] < lib_rope_particles[i][1][0])
xdir = 1;
var ydir = -1;
// Moving up?
if (lib_rope_particles[i][0][1] < lib_rope_particles[i][1][1])
ydir = 1;
var found = 0;
// Look for all possible places where the particle could move (from nearest to furthest).
for (var pos in LIB_ROPE_LandscapeMoveDirs)
{
// Moving left?
var xdir = -1;
if(particles[i][0][0] < particles[i][1][0])
xdir = 1;
var ydir = -1;
// Moving up?
if(particles[i][0][1] < particles[i][1][1])
ydir = 1;
var found = 0;
// Look for all possible places where the particle could move (from nearest to farest)
for(var pos in TestArray)
if (!GBackSolid(GetPartX(i) - GetX() + xdir * pos[0], GetPartY(i) - GetY() + ydir * pos[1]))
{
if(!GBackSolid(GetPartX(i)-GetX()+xdir*pos[0], GetPartY(i)-GetY()+ydir*pos[1]))
{
// Calculate the new position (if we don't move in a direction don't overwrite the old value)
var new = [0,0];
if(pos[0])
new[0] = (GetPartX(i)+xdir*pos[0])*LIB_ROPE_Precision-xdir*LIB_ROPE_Precision/2+xdir;
else
new[0] = particles[i][0][0];
if(pos[1])
new[1] = (GetPartY(i)+ydir*pos[1])*LIB_ROPE_Precision-ydir*LIB_ROPE_Precision/2+ydir;
else
new[1] = particles[i][0][1];
particles[i][4] = 1; // Notifier for applying friction after the constraints
particles[i][0] = new;
found = 1;
break;
}
// Calculate the new position (if we don't move in a direction don't overwrite the old value).
var new_pos = [0, 0];
if (pos[0])
new_pos[0] = (GetPartX(i) + xdir * pos[0]) * LIB_ROPE_Precision - xdir * LIB_ROPE_Precision / 2 + xdir;
else
new_pos[0] = lib_rope_particles[i][0][0];
if (pos[1])
new_pos[1] = (GetPartY(i) + ydir * pos[1]) * LIB_ROPE_Precision - ydir * LIB_ROPE_Precision / 2 + ydir;
else
new_pos[1] = lib_rope_particles[i][0][1];
// Notifier for applying friction after the constraints.
lib_rope_particles[i][4] = 1;
lib_rope_particles[i][0] = new_pos;
found = true;
break;
}
// No possibility to move the particle out? Then reset it. The old position should be valid
if(!found)
particles[i][0] = particles[i][1][:];
}
// No possibility to move the particle out? Then reset it. The old position should be valid.
if (!found)
lib_rope_particles[i][0] = lib_rope_particles[i][1][:];
}
}
return;
}
/** Satisfying the constraints for the particles
@ -513,31 +503,31 @@ public func ConstraintLandscape()
*/
private func SatisfyConstraints()
{
for(var j=0; j < LIB_ROPE_Iterations; j++)
for (var j = 0; j < LIB_ROPE_Iterations; j++)
{
ConstraintObjects();
ConstraintLength();
ConstraintLandscape();
}
// Apply friction for those how have the notifier for it.
// Friction just means that the velocity is divided by 2 to simulatie a friction force
for(var i=0; i < ParticleCount; i++)
// Apply friction for those who have the notifier for it.
// Friction just means that the velocity is divided by 2 to simulate a frictional force
for (var i = 0; i < lib_rope_particle_count; i++)
{
if(!particles[i][4]) continue;
var newvel = Vec_Sub(particles[i][0], particles[i][1]);
if (!lib_rope_particles[i][4])
continue;
var newvel = Vec_Sub(lib_rope_particles[i][0], lib_rope_particles[i][1]);
newvel = Vec_Div(newvel, 2);
particles[i][1] = Vec_Sub(particles[i][0], newvel);
lib_rope_particles[i][1] = Vec_Sub(lib_rope_particles[i][0], newvel);
}
return;
}
/** Returns the length of the rope
* @return the length of the rope
*/
// Returns the length of the rope.
public func GetLineLength()
{
var length_vertex = 0;
for(var i=1; i < ParticleCount; i++)
length_vertex += Distance(particles[i][0][0], particles[i][0][1], particles[i-1][0][0], particles[i-1][0][1]);
for (var i = 1; i < lib_rope_particle_count; i++)
length_vertex += Distance(lib_rope_particles[i][0][0], lib_rope_particles[i][0][1], lib_rope_particles[i - 1][0][0], lib_rope_particles[i - 1][0][1]);
return length_vertex;
}
@ -547,15 +537,15 @@ public func LengthAutoTryCount() { return 5; }
*/
public func ForcesOnObjects()
{
if(!length) return;
if(!lib_rope_length) return;
var redo = LengthAutoTryCount();
while(length_auto && redo)
while(lib_rope_length_auto && redo)
{
var speed = Vec_Length(Vec_Sub(particles[-1][0], particles[-1][1]));
if(length == GetMaxLength())
var speed = Vec_Length(Vec_Sub(lib_rope_particles[-1][0], lib_rope_particles[-1][1]));
if(lib_rope_length == GetMaxLength())
{
if(ObjContact(objects[1][0]))
if(ObjContact(lib_rope_objects[1][0]))
speed = 40;
else speed = 100;
}
@ -568,135 +558,96 @@ public func ForcesOnObjects()
if(PullObjects() )
for(var i = 0; i < 2; i++)
{
if(i == 1) j = ParticleCount-1;
var obj = objects[i][0];
if(i == 1) j = lib_rope_particle_count-1;
var obj = lib_rope_objects[i][0];
if(obj == nil || objects[i][1] == 0) continue;
if(obj == nil || lib_rope_objects[i][1] == 0) continue;
if(obj->Contained()) obj = obj->Contained();
/* var x = obj->GetX(LIB_ROPE_Precision), y = obj->GetY(LIB_ROPE_Precision);
obj->SetPosition(particles[j][0][0], particles[j][0][1], 1, LIB_ROPE_Precision);
if(obj->Stuck())
obj->SetPosition(x, y, 1, LIB_ROPE_Precision);*/
if( (obj->GetAction() == "Walk" || obj->GetAction() == "Scale" || obj->GetAction() == "Hangle"))
obj->SetAction("Jump");
if( obj->GetAction() == "Climb")
obj->SetAction("Jump");
obj->SetXDir( particles[j][0][0]-particles[j][1][0], LIB_ROPE_Precision);
obj->SetYDir( particles[j][0][1]-particles[j][1][1], LIB_ROPE_Precision);
obj->SetXDir( lib_rope_particles[j][0][0]-lib_rope_particles[j][1][0], LIB_ROPE_Precision);
obj->SetYDir( lib_rope_particles[j][0][1]-lib_rope_particles[j][1][1], LIB_ROPE_Precision);
}
}
public func PullObjects()
{
return !length_auto || length == GetMaxLength();
return !lib_rope_length_auto || lib_rope_length == GetMaxLength();
}
public func ObjContact(obj)
{
if(obj->Contained()) obj = obj->Contained();
if(obj->GetContact(-1)) return true;
if (obj->Contained())
obj = obj->Contained();
if (obj->GetContact(-1))
return true;
return false;
}
/** Just a helperfunction which has creaded the \c TestArray variable to test the landscape to move out particles
*/
/* Helperstuff */
/*-- Vector Operations --*/
// Addition of two vectors.
public func Vec_Add(array x, array y) { return [x[0] + y[0], x[1] + y[1]]; }
// Subtraction of two vectors.
public func Vec_Sub(array x, array y) { return [x[0] - y[0], x[1] - y[1]]; }
// Multiplication of a vector by a number.
public func Vec_Mul(array x, int i) { return [x[0] * i, x[1] * i]; }
// Division of a vector by a number.
public func Vec_Div(array x, int i) { return [x[0] / i, x[1] / i]; }
// Dot product of two vectors.
public func Vec_Dot(array x, array y) { return x[0] * y[0] + x[1] * y[1]; }
// Length of a vector.
public func Vec_Length(array x) { return Sqrt(x[0]**2 + x[1]**2); }
// Angle between two vectors.
public func Vec_Angle(array x, array y) { return Angle(x[0], x[1], y[0], y[1]); }
// Normalizes a vector to the given precision.
public func Vec_Normalize(array x, int precision) { return Vec_Div(Vec_Mul(x, precision), Vec_Length(x)); }
// Gives the the rounded x coordinate of particles index.
public func GetPartX(index) { return (lib_rope_particles[index][0][0] + LIB_ROPE_Precision / 2) / LIB_ROPE_Precision; }
// Gives the the rounded y coordinate of particles index.
public func GetPartY(index) { return (lib_rope_particles[index][0][1] + LIB_ROPE_Precision / 2) / LIB_ROPE_Precision; }
/*-- Helper Functions --*/
// Helper function which creates the test array variable to test the landscape to move out particles.
private func LogArray()
{
// Helperfunction which has created "TestArray"
var array = [];
for(var dist = 1; dist < 20; dist++)
for(var x = 0; x < 20; x++)
for(var y = 0; y < 20; y++)
{
if(Distance(0,0,x,y) != dist) continue;
array[GetLength(array)] = [x,y];
}
Log("%v", array);
// Helper function which creates the test array.
var test_array = [];
for (var dist = 1; dist < 20; dist++)
for (var x = 0; x < 20; x++)
for (var y = 0; y < 20; y++)
if (Distance(0, 0, x, y) == dist)
PushBack(test_array, [x,y]);
return Log("%v", test_array);
}
/** Testfunction which gives the speed of the particles
*/
// Helper function which gives the speed of the particles.
func LogSpeed()
{
// Helperfunction for Debugpurpose
var array = [];
for(var i=0; i < ParticleCount; i++)
var speed_array = [];
for(var i = 0; i < lib_rope_particle_count; i++)
{
var x = particles[i][0][:];
var oldx = particles[i][1][:];
array[GetLength(array)] = Distance(x[0]-oldx[0], x[1]-oldx[1]);
var x = lib_rope_particles[i][0][:];
var oldx = lib_rope_particles[i][1][:];
PushBack(speed_array, Distance(x[0] - oldx[0], x[1] - oldx[1]));
}
Log("%v", array);
return Log("%v", speed_array);
}
/** Addition of two vectors
* @param x vector 1
* @param y vector to add
* @param return vector \a x plus \a y
*/
public func Vec_Add(array x, array y) { return [x[0] + y[0], x[1] + y[1]]; }
/** Subtraction of two vectors
* @param x vector 1
* @param y vector to subtract
* @param return vector \a x minus \a y
*/
public func Vec_Sub(array x, array y) { return [x[0] - y[0], x[1] - y[1]]; }
/** Multiplication of a vector and a number
* @param x vector
* @param i number
* @param return \a i times \a x
*/
public func Vec_Mul(array x, int i) { return [x[0] * i, x[1] * i]; }
/** Division of a vector and a number
* @param x vector
* @param i number
* @param return \a x divided throught \a i
*/
public func Vec_Div(array x, int i) { return [x[0] / i, x[1] / i]; }
/** Dot product of two vectors
* @param x vector 1
* @param y vector 2
* @param return dot product between \a x and \a y
*/
public func Vec_Dot(array x, array y) { return x[0] * y[0] + x[1] * y[1]; }
/** Length of a vector
* @param x vector
* @param return length of vector \a a
*/
public func Vec_Length(array x) { return Sqrt(x[0] * x[0] + x[1] * x[1]); }
/** Angle between two vectors
* @param x vector 1
* @param y vector 2
* @param return angle between \a x and \a y
*/
public func Vec_Angle(array x, array y) { return Angle(x[0], x[1], y[0], y[1]); }
/** Normalizes a vector with precision
* @param x vector
* @param precision factor for the resultion length
* @param return the normalize vector with length 1*precision
*/
public func Vec_Normalize(array x, int precision) { return Vec_Div(Vec_Mul(x, precision), Vec_Length(x)); }
/** Gives the the rounded x coordinate of particles \a index
* @param index the particle which position is desired
* @param return the x coordinate of particle \a index
*/
public func GetPartX(index) { return (particles[index][0][0] + LIB_ROPE_Precision / 2) / LIB_ROPE_Precision; }
/** Gives the the rounded y coordinate of particles \a index
* @param index the particle which position is desired
* @param return the y coordinate of particle \a index
*/
public func GetPartY(index) { return (particles[index][0][1] + LIB_ROPE_Precision / 2) / LIB_ROPE_Precision; }