fix and improve grabbing onto ropeladders

liquid_container
Maikel de Vries 2016-04-11 21:04:51 +02:00
parent fe0440f881
commit 9bb2de333a
3 changed files with 201 additions and 138 deletions

View File

@ -6,7 +6,7 @@
#include Library_Ladder
local master, index;
local index;
local angle;
public func SetAngle(int new_angle)
@ -17,8 +17,10 @@ public func SetAngle(int new_angle)
// 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;
// First perform setting the master in the library function.
_inherited(new_master, new_index, ...);
index = new_index;
return;
}
// Returns whether the ladder can be climbed.

View File

@ -1,20 +1,16 @@
/**
Ladder Climbing
Gives the ability to clonks climb on ladders.
Gives the ability to clonks climb on ladders, to be included by the clonk.
@author Randrian
*/
local jump_startcall;
local no_ladder_counter;
public func GetTurnPhase() { return _inherited(...); }
public func Definition(proplist def)
{
// Only add action if included by clonk.
if (!def.ActMap)
return _inherited(def);
// Add actions for climbing and overload jumping actions to search for ladders.
def.ActMap = {
Prototype = def.ActMap,
Climb = {
@ -30,24 +26,27 @@ public func Definition(proplist def)
Jump = {
Prototype = def.ActMap.Jump,
StartCall = "StartSearchLadder",
// save old phasecall of jump
// Save the old phasecall of the jump.
StartCallLadderOverloaded = def.ActMap.Jump.StartCall
},
WallJump = {
Prototype = def.ActMap.WallJump,
StartCall = "StartSearchLadder",
// save old phasecall of jump
// Save the old phasecall of the wall jump.
StartCallLadderOverloaded = def.ActMap.WallJump.StartCall
}
};
_inherited(def);
return _inherited(def);
}
public func StartScale()
{
// Should be overloaded, and add a climb animation here
return _inherited(...);
}
public func GetTurnPhase() { return _inherited(...); }
public func SetTurnType() { return _inherited(...); }
public func SetHandAction() { return _inherited(...); }
// Should be overloaded, and add a climb animation here
public func StartScale() { return _inherited(...); }
/*-- Ladder Searching --*/
public func StartSearchLadder()
{
@ -56,8 +55,9 @@ public func StartSearchLadder()
Call(this.ActMap.Jump.StartCallLadderOverloaded);
if (GetAction() == "WallJump" && this.ActMap.WallJump.StartCallLadderOverloaded)
Call(this.ActMap.WallJump.StartCallLadderOverloaded);
// Add an effect to search for ladders.
if (!GetEffect("InSearchLadder", this))
AddEffect("IntSearchLadder", this, 1, 5, this);
AddEffect("IntSearchLadder", this, 1, 2, this);
FxIntSearchLadderTimer();
return;
}
@ -76,25 +76,19 @@ public func FxIntSearchLadderTimer(object target, proplist effect, int time)
if (GetAction() != "Jump" && GetAction() != "WallJump")
return FX_Execute_Kill;
// Don't search for ladders if the counter is non-zero.
if (no_ladder_counter > 0)
{
no_ladder_counter--;
return FX_OK;
}
// Find a ladder.
// Find a ladder which can be climbed.
var ladder;
for (ladder in FindObjects(Find_AtRect(-5, -10, 10, 8), Find_Func("IsLadder"), Find_NoContainer(), Find_Layer(GetObjectLayer())))
{
if (!ladder->~CanNotBeClimbed())
{
SetAction("Climb");
ladder->~OnLadderGrab(this);
PlayAnimation(GetLadderScaleAnimation(), CLONK_ANIM_SLOT_Movement, Anim_Y(0, GetAnimationLength(GetLadderScaleAnimation()), 0, 15), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
AddEffect("IntClimbControl", this, 1, 1, this, nil, ladder);
return FX_Execute_Kill;
}
// Don't climb ladders that are blocked.
if (ladder->~CanNotBeClimbed() || IsBlockedLadder(ladder))
continue;
SetAction("Climb");
ladder->~OnLadderGrab(this);
PlayAnimation(GetLadderScaleAnimation(), CLONK_ANIM_SLOT_Movement, Anim_Y(0, GetAnimationLength(GetLadderScaleAnimation()), 0, 15), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
AddEffect("IntClimbControl", this, 1, 1, this, nil, ladder);
return FX_Execute_Kill;
}
return FX_OK;
}
@ -103,123 +97,140 @@ public func FxIntSearchLadderStop(object target, proplist effect, reason, tmp)
{
if (tmp)
return FX_OK;
no_ladder_counter = 0;
return FX_OK;
}
public func FxIntClimbControlStart(object target, proplist effect, tmp, object ladder)
/*-- Ladder Block --*/
private func AddLadderBlock(object ladder, int duration)
{
AddEffect("IntBlockLadder", this, 100, duration, this, nil, ladder);
return;
}
private func IsBlockedLadder(object ladder)
{
var index = 0;
var fx;
while (fx = GetEffect("IntBlockLadder", this, index++))
if (fx.ladder->IsSameLadder(ladder))
return true;
return false;
}
public func FxIntBlockLadderStart(object target, effect fx, int tmp, object to_ladder)
{
if (tmp)
return FX_OK;
fx.ladder = to_ladder;
return FX_OK;
}
public func FxIntBlockLadderTimer(object target, effect fx, int time)
{
return FX_Execute_Kill;
}
/*-- Ladder Control --*/
public func FxIntClimbControlStart(object target, effect fx, int tmp, object ladder)
{
if (tmp)
return FX_OK;
effect.ladder = ladder;
fx.ladder = ladder;
SetXDir(0);
SetYDir(0);
SetComDir(COMD_Stop);
effect.odd = 0; // odd or even segment?
// Start on an even segment.
fx.odd = 0;
// Correctly initalize the relative y-position of the clonk to the segment.
var data = fx.ladder->GetLadderData();
var sy = data[1], ey = data[3];
var cy = GetY(1000);
var posy = 0;
if (ey - sy != 0)
posy = 100 * (cy - sy) / (ey - sy);
fx.pos = BoundBy(posy, 0, 100);
// Set some stuff for the clonk.
SetHandAction(1);
SetTurnType(1);
return FX_OK;
}
public func SetTurnType() { return _inherited(...); }
public func SetHandAction() { return _inherited(...); }
public func LadderStep(target, effect, fUp)
public func LadderStep(object target, effect fx, int climb_direction)
{
if (fUp == 1)
if (climb_direction != 1 && climb_direction != -1)
return fx.ladder != nil;
// Store old segment to forward to blocking.
var old_ladder_segment = fx.ladder;
// Increase position depending on direction and move to new segment if needed.
fx.pos += 10 * climb_direction;
if (fx.pos > 100)
{
effect.pos += 10;
if (effect.pos > 100)
fx.pos = 0;
fx.ladder = fx.ladder->GetNextLadder();
fx.odd = !fx.odd;
}
if (fx.pos < 0)
{
fx.pos = 100;
fx.ladder = fx.ladder->GetPreviousLadder();
fx.odd = !fx.odd;
}
// If no ladder has been found scale or jump off.
if (fx.ladder == nil)
{
var contact = GetContact(-1);
if (contact & CNAT_Left || contact & CNAT_Right)
{
effect.pos = 0;
effect.ladder = effect.ladder->GetNextLadder();
effect.odd = !effect.odd;
SetAction("Scale");
old_ladder_segment->~OnLadderReleased(this);
return false;
}
if (effect.ladder == nil)
AddLadderBlock(old_ladder_segment, 10);
SetAction("Jump");
// Increase speed if moving up.
if (climb_direction == 1)
{
var contact = GetContact(-1);
if (contact & CNAT_Left || contact & CNAT_Right)
{
SetAction("Scale");
return false;
}
no_ladder_counter = 5;
SetAction("Jump");
SetXDir(-5+10*GetDir());
SetXDir(-5 + 10 * GetDir());
SetYDir(-5);
return false;
}
old_ladder_segment->~OnLadderReleased(this);
return false;
}
else
{
effect.pos -= 10;
if(effect.pos < 0)
{
effect.pos = 100;
effect.ladder = effect.ladder->GetPreviousLadder();
effect.odd = !effect.odd;
}
if (effect.ladder == nil)
{
var contact = GetContact(-1);
if (contact & CNAT_Left || contact & CNAT_Right)
{
SetAction("Scale");
return false;
}
no_ladder_counter = 5;
SetAction("Jump");
return false;
}
}
if (effect.ladder == nil) return false;
return true;
}
public func FxIntClimbControlTimer(object target, proplist effect, int time)
public func FxIntClimbControlTimer(object target, effect fx, int time)
{
if (GetAction() != "Climb" || Contained())
return FX_Execute_Kill;
if (effect.ladder && effect.ladder->~CanNotBeClimbed(true))
effect.ladder = nil;
if (!effect.ladder)
if (!fx.ladder || fx.ladder->~CanNotBeClimbed(true))
{
no_ladder_counter = 5;
AddLadderBlock(fx.ladder, 5);
SetAction("Jump");
SetXDir(-5 + 10 * GetDir());
SetYDir(-5);
return FX_Execute_Kill;
}
// Progress
var step = 0;
// Progress movement in the controlled direction.
var climb_direction = 0;
if (GetComDir() == COMD_Down)
step = -1;
climb_direction = -1;
if (GetComDir() == COMD_Up)
step = 1;
if (step && !LadderStep(target, effect, step))
{
var contact = GetContact(-1);
if (contact & CNAT_Left || contact & CNAT_Right)
SetAction("Scale");
else
{
no_ladder_counter = 5;
SetAction("Jump");
if (step == 1) // For Up add some speed
{
SetXDir(-5 + 10 * GetDir());
SetYDir(-5);
no_ladder_counter = 10;
}
}
climb_direction = 1;
// LadderStep advances the ladder segment or the ladder position.
if (climb_direction && !LadderStep(target, fx, climb_direction))
return FX_Execute_Kill;
}
var data = effect.ladder->GetLadderData();
// Move the clonk along the ladder according to the new pos/segment.
var data = fx.ladder->GetLadderData();
var startx = data[0], starty = data[1], endx = data[2], endy = data[3], angle = data[4];
var x = startx + (endx-startx) * effect.pos / 100 + 5000 - 100 * GetTurnPhase();
var y = starty + (endy-starty) * effect.pos / 100;
var x = startx + (endx - startx) * fx.pos / 100 + 5000 - 100 * GetTurnPhase();
var y = starty + (endy - starty) * fx.pos / 100;
var lx = LadderToLandscapeCoordinates(x);
var ly = LadderToLandscapeCoordinates(y);
var old_x = GetX(), old_y = GetY();
@ -229,6 +240,8 @@ public func FxIntClimbControlTimer(object target, proplist effect, int time)
SetXDir(0);
SetYDir(0);
SetLadderRotation(-angle, x - GetX() * 1000, y - GetY() * 1000);
// Handle if the clonk gets stuck.
if (Stuck())
{
var dir = -1;
@ -237,40 +250,47 @@ public func FxIntClimbControlTimer(object target, proplist effect, int time)
for (var i = 1; i <= 5; i++)
{
SetPosition(LadderToLandscapeCoordinates(x) + i * dir, LadderToLandscapeCoordinates(y));
if (!Stuck()) break;
if (!Stuck())
break;
}
if (Stuck()) SetPosition(LadderToLandscapeCoordinates(x) + 5 * dir, LadderToLandscapeCoordinates(y));
if (Stuck())
SetPosition(LadderToLandscapeCoordinates(x) + 5 * dir, LadderToLandscapeCoordinates(y));
}
if (Stuck())
{
// Revert Position and step
// Revert Position and step.
SetPosition(old_x, old_y);
if (step)
LadderStep(target, effect, -step);
// if we are to far left or right try to turn
if (climb_direction)
LadderStep(target, fx, -climb_direction);
// If we are too far left or right try to turn.
if (GetDir() == DIR_Left && LadderToLandscapeCoordinates(x) - 2 > GetX())
{
SetComDir(COMD_Right);
SetDir(DIR_Right);
}
else if (GetDir() == DIR_Right && LadderToLandscapeCoordinates(x)+2 < GetX())
else if (GetDir() == DIR_Right && LadderToLandscapeCoordinates(x) + 2 < GetX())
{
SetComDir(COMD_Left);
SetDir(DIR_Left);
}
}
else effect.ladder->~OnLadderClimb(this);
// Make the animation synchron with movement TODO: this only makes the feet synchronous for the arms the animation has to be adapted
else
{
fx.ladder->~OnLadderClimb(this);
}
// Make the animation synchron with movement.
// TODO: this only makes the feet synchronous for the arms the animation has to be adapted.
var animation = GetRootAnimation(5);
if (animation != nil)
{
if (GetAnimationName(animation) != nil)
{
var length = GetAnimationLength(GetAnimationName(animation));
var pos = effect.pos * length / 200 + length / 2 * effect.odd;
var pos = fx.pos * length / 200 + length / 2 * fx.odd;
SetAnimationPosition(animation, Anim_Const(pos));
}
}
// Start walking or hangling if the clonk makes contact with the floor or ceiling.
var contact = GetContact(-1);
if (contact)
{
@ -287,14 +307,15 @@ public func FxIntClimbControlTimer(object target, proplist effect, int time)
SetComDir(COMD_Left);
SetDir(0);
}
return -1;
return FX_Execute_Kill;
}
if (contact & CNAT_Bottom && GetComDir() == COMD_Down)
{
SetAction("Walk");
return -1;
return FX_Execute_Kill;
}
}
return FX_OK;
}
private func LadderToLandscapeCoordinates(int x)
@ -303,15 +324,20 @@ private func LadderToLandscapeCoordinates(int x)
return (x + 500) / 1000;
}
public func FxIntClimbControlStop(target, effect)
public func FxIntClimbControlStop(object target, effect fx, int reason, bool tmp)
{
if (tmp)
return FX_OK;
if (GetAction() == "Climb")
SetAction("Walk");
if (fx.ladder)
fx.ladder->~OnLadderReleased(this);
SetLadderRotation(0);
SetHandAction(0);
return FX_OK;
}
public func FxIntClimbControlControl(object target, proplist effect, int ctrl, int x, int y, int strength, bool repeat, bool release)
public func FxIntClimbControlControl(object target, effect fx, int ctrl, int x, int y, int strength, bool repeat, bool release)
{
// Only handle movement controls.
if (ctrl != CON_Up && ctrl != CON_Down && ctrl != CON_Right && ctrl != CON_Left)
@ -319,16 +345,24 @@ public func FxIntClimbControlControl(object target, proplist effect, int ctrl, i
// Perform actions on key down and not on release.
if (release)
return false;
// Move up and down by setting com dir.
if (ctrl == CON_Up)
{
SetComDir(COMD_Up);
else if (ctrl == CON_Down)
return true;
}
if (ctrl == CON_Down)
{
SetComDir(COMD_Down);
return true;
}
else if (ctrl == CON_Left)
// Handle left and right controls.
if (ctrl == CON_Left)
{
if (GetDir() == DIR_Left)
{
// Switch to the other side of the ladder.
if (GetComDir() == COMD_Stop)
{
SetPosition(GetX() - 10, GetY());
@ -343,17 +377,22 @@ public func FxIntClimbControlControl(object target, proplist effect, int ctrl, i
}
else
{
no_ladder_counter = 5;
// Let go of the ladder and remove the effect.
AddLadderBlock(fx.ladder, 5);
if (GetComDir() == COMD_Up)
this->ObjectCommand("Jump");
else
this->ObjectComLetGo(-10);
RemoveEffect(nil, target, fx);
}
return true;
}
else if (ctrl == CON_Right)
if (ctrl == CON_Right)
{
if (GetDir() == DIR_Right)
{
// Switch to the other side of the ladder.
if (GetComDir() == COMD_Stop)
{
SetPosition(GetX() + 10, GetY());
@ -368,12 +407,15 @@ public func FxIntClimbControlControl(object target, proplist effect, int ctrl, i
}
else
{
no_ladder_counter = 5;
// Let go of the ladder and remove the effect.
AddLadderBlock(fx.ladder, 5);
if (GetComDir() == COMD_Up)
this->ObjectCommand("Jump");
else
this->ObjectComLetGo(10);
RemoveEffect(nil, target, fx);
}
return true;
}
return true;
}

View File

@ -1,24 +1,43 @@
/**
Ladder Control
Containes the basic functionality for ladders.
Containes the basic functionality for ladder segments.
@author Randrian
*/
local master;
local next_segment;
local prev_segment;
public func IsLadder() { return true; }
public func SetMaster(object new_master)
{
master = new_master;
return;
}
public func GetMaster()
{
return master;
}
// Returns whether this segment and the other one are from the same ladder.
public func IsSameLadder(object other_segment)
{
return GetMaster() == other_segment->GetMaster();
}
// Returns the segment (start x, start y, end x, end y, angle) on which the clonk can climb.
// The coordinate value must be specified with a precision of a 1000.
public func GetLadderData()
{
// 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),
GetX(1000) + 1000 * GetVertex(0, 0),
GetY(1000) + 1000 * GetVertex(0, 1),
GetX(1000) + 1000 * GetVertex(1, 0),
GetY(1000) + 1000 * GetVertex(1, 1),
0
];
}