Tweak the "corner scale" behaviour

Instead of teleporting from sticking with the left/rightmost vertex to the
want to standing on the lowest one at the same position, the Clonk can now
climb using the lowest vertex alone. That means the teleport only needs to
cover only one pixel each in x and y direction to go from sticking to the
side of the landscape pixel to sticking on top of the same pixel.

Also remove some unnecessary x/ydir resets and make comdir in the direction
of the wall the Clonk is scaling keep the up/down direction instead of only
going up.
floating-point
Günther Brammer 2012-06-08 16:17:42 +02:00
parent e68f83f02b
commit 944ca60910
6 changed files with 83 additions and 124 deletions

View File

@ -541,20 +541,11 @@ func StopScale()
if(GetAction() != "Scale") RemoveEffect("IntScale", this);
}
func CheckPosition(int off_x, int off_y)
{
var free = 1;
SetPosition(GetX()+off_x, GetY()+off_y);
if(Stuck()) free = 0;
SetPosition(GetX()-off_x, GetY()-off_y);
return free;
}
func CheckScaleTop()
{
// Test whether the clonk has reached a top corner
if(GBackSolid(-8+16*GetDir(),-8)) return false;
if(!CheckPosition(-7*(-1+2*GetDir()),-17)) return false;
// That is, the leg vertices are the only ones attached to the wall
if(GBackSolid(-3+6*GetDir(),-3) || GBackSolid(-5+10*GetDir(),2)) return false;
return true;
}
@ -573,24 +564,20 @@ func FxIntScaleTimer(target, number, time)
{
// If the animation is not already set
var dist = 0;
while(!GBackSolid(-8+16*GetDir(),dist-8) && dist < 10) dist++;
while(!(GBackSolid(-3+6*GetDir(),dist-3) || GBackSolid(-5+10*GetDir(),dist+2)) && dist < 8) dist++;
dist *= 100;
dist += GetY(100)-GetY()*100;
// add the fractional part of the position (dist counts in the opposite direction of y)
dist -= GetY(100)-GetY()*100;
if(number.animation_mode != 1)
{
number.animation_id = PlayAnimation("ScaleTop", 5, Anim_Const(GetAnimationLength("ScaleTop")*dist/1000), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
number.animation_id = PlayAnimation("ScaleTop", 5, Anim_Const(GetAnimationLength("ScaleTop")*dist/800), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
number.animation_mode = 1;
}
this.dist = dist;
SetAnimationPosition(number.animation_id, Anim_Const(GetAnimationLength("ScaleTop")*dist/1000));
SetAnimationPosition(number.animation_id, Anim_Const(GetAnimationLength("ScaleTop")*dist/800));
// The animation's graphics has to be shifet a bit to adjust to the clonk movement
var pos = GetAnimationPosition(number.animation_id);
//var percent = pos*1000/GetAnimationLength("ScaleTop");
var offset_list = [[0,0], [0,-1], [-1,-2], [-2,-3], [-2,-5], [-2,-7], [-4,-8], [-6,-10], [-7,-9], [-8,-8]];
var offset = offset_list[dist/100-1];
var rot = 0;
if(dist/100-1 > 5) rot = 5*dist/100-25;
SetScaleRotation(0, -offset[0]*(-1+2*GetDir())*1000, offset[1]*1000, -rot*(-1+2*GetDir()), 0, 1);
SetScaleRotation(0, 0, 0, 0, 0, 1);
}
else if(!GBackSolid(-10+20*GetDir(), 8))
{
@ -1367,4 +1354,4 @@ func StartEat()
PlayAnimation("Eat", 10, Anim_Linear(0,0, GetAnimationLength("Eat"), 45, ANIM_Remove), Anim_Linear(0, 0, 1000, 5, ANIM_Remove));
// Update carried items
UpdateAttach();
}
}

View File

@ -5,11 +5,11 @@ Category=C4D_Living
Width=8
Height=20
Offset=-4,-10
Vertices=7
VertexX=0,0,0,-2,2,-4,4
VertexY=2,-7,9,-3,-3,2,2
VertexCNAT=0,4,8,1,2,1,2
VertexFriction=300,300,100,300,300,300,300
Vertices=9
VertexX= 0, 0, 0, -2, 2, -4, 4, -2, 2
VertexY= 2, -7, 9, -3, -3, 2, 2, 6, 6
VertexCNAT= 0, 4, 11, 1, 2, 1, 2, 1, 2
VertexFriction=300,300,100,300,300,300,300,300,300
Value=25
Mass=50
Collection=-8,-10,16,27

View File

@ -317,37 +317,46 @@ void C4Object::DoMovement()
// Move to target
do
{
bool at_xovr = false, at_yovr = false;
// Set next step target
int step_x = 0, step_y = 0;
if (Abs<C4Real>(fix_x - ctcox) > C4REAL10(5))
step_x = Sign<C4Real>(new_x - fix_x);
if (Abs<C4Real>(fix_y - ctcoy) > C4REAL10(5))
step_y = Sign<C4Real>(new_y - fix_y);
int32_t ctx = GetX() + step_x; int32_t cty = GetY() + step_y;
if (ctcox != GetX())
step_x = Sign(ctcox - GetX());
else if (ctcoy != GetY())
step_y = Sign(ctcoy - GetY());
int32_t ctx = GetX() + step_x;
int32_t cty = GetY() + step_y;
// Attachment check
if (!Shape.Attach(ctx,cty,Action.t_attach))
fNoAttach=1;
else
{
// Attachment change to ctx/cty overrides ctco target
if (cty != GetY() + step_y) at_yovr = true;
if (ctx != GetX() + step_x) at_xovr = true;
if (ctx != GetX() + step_x)
{
ctcox = ctx; xdir = Fix0; new_x = itofix(ctx);
}
if (cty != GetY() + step_y)
{
ctcoy = cty; ydir = Fix0; new_y = itofix(cty);
}
}
// Contact check & evaluation
if ((iContact=ContactCheck(ctx,cty)))
{
fAnyContact=true; iContacts |= t_contact;
// Abort movement
ctcox=GetX(); new_x = fix_x;
ctcoy=GetY(); new_y = fix_y;
if (ctx != GetX())
{
ctx = ctcox = GetX(); new_x = fix_x;
}
if (cty != GetY())
{
cty = ctcoy = GetY(); new_y = fix_y;
}
}
else // Continue free movement
DoMotion(ctx-GetX(),cty-GetY());
if (at_xovr) { ctcox=GetX(); xdir=Fix0; new_x = fix_x; }
if (at_yovr) { ctcoy=GetY(); ydir=Fix0; new_y = fix_y; }
DoMotion(ctx - GetX(), cty - GetY());
}
while (Abs<C4Real>(fix_x - ctcox) > C4REAL10(5) || Abs<C4Real>(fix_y - ctcoy) > C4REAL10(5));
while (ctcox != GetX() || ctcoy != GetY());
}
if(fix_x != new_x || fix_y != new_y)

View File

@ -3086,14 +3086,9 @@ void C4Object::NoAttachAction()
}
}
bool ContactVtxCNAT(C4Object *cobj, BYTE cnat_dir);
void C4Object::ContactAction()
{
// Take certain action on contact. Evaluate t_contact-CNAT and Procedure.
C4Real last_xdir;
int32_t iDir;
// Determine Procedure
C4PropList* pActionDef = GetAction();
@ -3112,25 +3107,17 @@ void C4Object::ContactAction()
if (ObjectActionFlat(this,Action.Dir)) return;
if (OCF & OCF_HitSpeed3)
if (ObjectActionKneel(this)) return;
// Walk, but keep horizontal momentum (momentum is reset
// by ObjectActionWalk) to avoid walk-jump-flipflop on
// sideways corner hit if initial walk acceleration is
// not enough to reach the next pixel for attachment.
// Urks, all those special cases...
last_xdir=xdir;
ObjectActionWalk(this);
xdir=last_xdir;
ydir = 0;
return;
case DFA_SCALE:
// Scale up: try corner scale
if (!ComDirLike(Action.ComDir, COMD_Down))
// Scale down: stand
if (ComDirLike(Action.ComDir, COMD_Down))
{
if (ObjectActionCornerScale(this)) return;
ObjectActionStand(this);
return;
}
// Any other: Stand
ObjectActionStand(this);
return;
break;
case DFA_DIG:
// no special action
break;
@ -3138,7 +3125,7 @@ void C4Object::ContactAction()
// Try corner scale out
if (!GBackLiquid(GetX(), GetY() - 1))
if (ObjectActionCornerScale(this)) return;
return;
break;
}
//------------------------------- Hit Ceiling -----------------------------------------
@ -3152,9 +3139,11 @@ void C4Object::ContactAction()
// Scale: Try hangle, else stop if going upward
if (ComDirLike(Action.ComDir, COMD_Up))
{
iDir=DIR_Left;
if (Action.Dir==DIR_Left) { iDir=DIR_Right; }
if (ObjectActionHangle(this,iDir)) return;
if (ObjectActionHangle(this))
{
SetDir(Action.Dir == DIR_Left ? DIR_Right : DIR_Left);
return;
}
Action.ComDir=COMD_Stop;
}
break;
@ -3162,8 +3151,8 @@ void C4Object::ContactAction()
// Jump: Try hangle, else bounce off
// High Speed Flight: Tumble
if ((OCF & OCF_HitSpeed3) || fDisabled)
{ ObjectActionTumble(this,Action.Dir,Fix0,Fix0); break; }
if (ObjectActionHangle(this,Action.Dir)) return;
{ ObjectActionTumble(this,Action.Dir,xdir,ydir); break; }
if (ObjectActionHangle(this)) return;
break;
case DFA_DIG:
// No action
@ -3186,12 +3175,14 @@ void C4Object::ContactAction()
else if (ObjectActionScale(this,DIR_Left)) return;
break;
case DFA_WALK:
// Walk: Try scale, else stop
// Walk: Try scale
if (ComDirLike(Action.ComDir, COMD_Left))
{
if (ObjectActionScale(this,DIR_Left)) return;
// Else stop
Action.ComDir=COMD_Stop;
if (ObjectActionScale(this,DIR_Left))
{
ydir = C4REAL100(-1);
return;
}
}
// Heading away from solid
if (ComDirLike(Action.ComDir, COMD_Right))
@ -3208,10 +3199,12 @@ void C4Object::ContactAction()
if (ObjectActionCornerScale(this)) return;
return;
case DFA_HANGLE:
// Hangle: Try scale, else stop
// Hangle: Try scale
if (ObjectActionScale(this,DIR_Left))
{
ydir = C4REAL100(1);
return;
Action.ComDir=COMD_Stop;
}
return;
case DFA_DIG:
// Dig: no action
@ -3232,11 +3225,14 @@ void C4Object::ContactAction()
else if (ObjectActionScale(this,DIR_Right)) return;
break;
case DFA_WALK:
// Walk: Try scale, else stop
// Walk: Try scale
if (ComDirLike(Action.ComDir, COMD_Right))
{
if (ObjectActionScale(this,DIR_Right)) return;
Action.ComDir=COMD_Stop;
if (ObjectActionScale(this,DIR_Right))
{
ydir = C4REAL100(-1);
return;
}
}
// Heading away from solid
if (ComDirLike(Action.ComDir, COMD_Left))
@ -3254,10 +3250,12 @@ void C4Object::ContactAction()
// Skip to enable walk out
return;
case DFA_HANGLE:
// Hangle: Try scale, else stop
// Hangle: Try scale
if (ObjectActionScale(this,DIR_Right))
{
ydir = C4REAL100(1);
return;
Action.ComDir=COMD_Stop;
}
return;
case DFA_DIG:
// Dig: no action
@ -3540,10 +3538,13 @@ void C4Object::ExecAction()
case DFA_SCALE:
{
int ComDir = Action.ComDir;
if (Action.Dir == DIR_Left && ComDir == COMD_Left)
ComDir = COMD_Up;
else if (Action.Dir == DIR_Right && ComDir == COMD_Right)
ComDir = COMD_Up;
if ((Action.Dir == DIR_Left && ComDir == COMD_Left) || (Action.Dir == DIR_Right && ComDir == COMD_Right))
{
if (ydir > 0)
ComDir = COMD_Down;
else
ComDir = COMD_Up;
}
switch (ComDir)
{
case COMD_Up: case COMD_UpRight: case COMD_UpLeft:

View File

@ -48,7 +48,6 @@ bool CreateConstructionSite(int32_t ctx, int32_t bty, C4ID strid, int32_t owner,
bool ObjectActionWalk(C4Object *cObj)
{
if (!cObj->SetActionByName("Walk")) return false;
cObj->xdir=cObj->ydir=0;
return true;
}
@ -104,14 +103,12 @@ bool ObjectActionGetPunched(C4Object *cObj, C4Real xdir, C4Real ydir)
bool ObjectActionKneel(C4Object *cObj)
{
if (!cObj->SetActionByName("KneelDown")) return false;
cObj->xdir=cObj->ydir=0;
return true;
}
bool ObjectActionFlat(C4Object *cObj, int32_t dir)
{
if (!cObj->SetActionByName("FlatUp")) return false;
cObj->xdir=cObj->ydir=0;
cObj->SetDir(dir);
return true;
}
@ -119,16 +116,13 @@ bool ObjectActionFlat(C4Object *cObj, int32_t dir)
bool ObjectActionScale(C4Object *cObj, int32_t dir)
{
if (!cObj->SetActionByName("Scale")) return false;
cObj->xdir=cObj->ydir=0;
cObj->SetDir(dir);
return true;
}
bool ObjectActionHangle(C4Object *cObj, int32_t dir)
bool ObjectActionHangle(C4Object *cObj)
{
if (!cObj->SetActionByName("Hangle")) return false;
cObj->xdir=cObj->ydir=0;
cObj->SetDir(dir);
return true;
}
@ -164,7 +158,7 @@ bool ObjectActionPush(C4Object *cObj, C4Object *target)
return cObj->SetActionByName("Push",target);
}
bool CornerScaleOkay(C4Object *cObj, int32_t iRangeX, int32_t iRangeY)
static bool CornerScaleOkay(C4Object *cObj, int32_t iRangeX, int32_t iRangeY)
{
int32_t ctx,cty;
cty=cObj->GetY()-iRangeY;
@ -179,31 +173,10 @@ bool CornerScaleOkay(C4Object *cObj, int32_t iRangeX, int32_t iRangeY)
return false;
}
bool CheckCornerScale(C4Object *cObj, int32_t &iRangeX, int32_t &iRangeY)
{
for (iRangeX=CornerRange; iRangeX>=1; iRangeX--)
for (iRangeY=CornerRange; iRangeY>=1; iRangeY--)
if (CornerScaleOkay(cObj,iRangeX,iRangeY))
return true;
return false;
}
bool ObjectActionCornerScale(C4Object *cObj)
{
int32_t iRangeX,iRangeY;
// Scaling: check range max to min
if (cObj->GetProcedure()==DFA_SCALE)
{
if (!CheckCornerScale(cObj,iRangeX,iRangeY)) return false;
}
// Swimming: check range min to max
else
{
iRangeY=2;
while (!CornerScaleOkay(cObj,iRangeY,iRangeY))
{ iRangeY++; if (iRangeY>CornerRange) return false; }
iRangeX=iRangeY;
}
int32_t iRangeX = 1, iRangeY = 1;
if (!CornerScaleOkay(cObj,iRangeX,iRangeY)) return false;
// Do corner scale
if (!cObj->SetActionByName("KneelUp"))
cObj->SetActionByName("Walk");
@ -234,17 +207,6 @@ bool ObjectComMovement(C4Object *cObj, int32_t comdir)
return true;
}
bool ObjectComTurn(C4Object *cObj)
{
// turn around, if standing still
if (!cObj->xdir && cObj->GetProcedure() == DFA_WALK)
{
cObj->SetDir(1-cObj->Action.Dir);
return true;
}
return false;
}
bool ObjectComStop(C4Object *cObj)
{
// Cease current action

View File

@ -43,7 +43,7 @@ bool ObjectActionGetPunched(C4Object *cObj, C4Real xdir, C4Real ydir);
bool ObjectActionKneel(C4Object *cObj);
bool ObjectActionFlat(C4Object *cObj, int32_t dir);
bool ObjectActionScale(C4Object *cObj, int32_t dir);
bool ObjectActionHangle(C4Object *cObj, int32_t dir);
bool ObjectActionHangle(C4Object *cObj);
bool ObjectActionThrow(C4Object *cObj, C4Object *pThing=NULL);
bool ObjectActionDig(C4Object *cObj);
bool ObjectActionPush(C4Object *cObj, C4Object *pTarget);