package rabbitescape.engine.behaviours;
import static rabbitescape.engine.ChangeDescription.State.*;
import static rabbitescape.engine.Direction.*;
import static rabbitescape.engine.Block.Shape.*;
import rabbitescape.engine.*;
import rabbitescape.engine.ChangeDescription.State;
public class Walking extends Behaviour
{
@Override
public void cancel()
{
}
private static class StateCalc
{
private final BehaviourTools t;
StateCalc( BehaviourTools t )
{
this.t = t;
}
public State newState()
{
if ( t.isOnUpSlope() )
{
Block aboveNext = t.blockAboveNext();
Block above = t.blockAbove();
int nextX = t.nextX();
int nextY = t.rabbit.y - 1;
if
(
t.isWall( aboveNext )
|| Blocking.blockerAt( t.world, nextX, nextY )
|| t.isRoof( above )
|| ( t.isCresting() && Blocking.blockerAt( t.world, nextX, t.rabbit.y ) )
)
{
return rl(
RABBIT_TURNING_RIGHT_TO_LEFT_RISING,
RABBIT_TURNING_LEFT_TO_RIGHT_RISING
);
}
else if ( t.isUpSlope( aboveNext ) )
{
return rl(
RABBIT_RISING_RIGHT_CONTINUE,
RABBIT_RISING_LEFT_CONTINUE
);
}
else if ( t.isDownSlope( t.blockNext() ) )
{
return rl(
RABBIT_RISING_AND_LOWERING_RIGHT,
RABBIT_RISING_AND_LOWERING_LEFT
);
}
else
{
return rl(
RABBIT_RISING_RIGHT_END,
RABBIT_RISING_LEFT_END
);
}
}
else if ( t.isOnDownSlope() )
{
int nextX = t.nextX();
int nextY = t.rabbit.y + 1;
Block next = t.blockNext();
Block belowNext = t.blockBelowNext();
if (
t.isWall( next )
|| Blocking.blockerAt( t.world, nextX, nextY )
|| ( t.isValleying() && Blocking.blockerAt( t.world, nextX, t.rabbit.y ) )
)
{
return rl(
RABBIT_TURNING_RIGHT_TO_LEFT_LOWERING,
RABBIT_TURNING_LEFT_TO_RIGHT_LOWERING
);
}
else if ( t.isUpSlope( next ) )
{
return rl(
RABBIT_LOWERING_AND_RISING_RIGHT,
RABBIT_LOWERING_AND_RISING_LEFT
);
}
else if ( t.isDownSlope( belowNext ) )
{
return rl(
RABBIT_LOWERING_RIGHT_CONTINUE,
RABBIT_LOWERING_LEFT_CONTINUE
);
}
else
{
if ( Blocking.blockerAt( t.world, nextX, t.rabbit.y ) )
{
return rl(
RABBIT_TURNING_RIGHT_TO_LEFT_LOWERING,
RABBIT_TURNING_LEFT_TO_RIGHT_LOWERING
);
}
else
{
return rl(
RABBIT_LOWERING_RIGHT_END,
RABBIT_LOWERING_LEFT_END
);
}
}
}
else // On flat ground now
{
int nextX = t.nextX();
int nextY = t.rabbit.y;
Block next = t.blockNext();
if
(
t.isWall( next )
|| Blocking.blockerAt( t.world, nextX, nextY )
)
{
return rl(
RABBIT_TURNING_RIGHT_TO_LEFT,
RABBIT_TURNING_LEFT_TO_RIGHT
);
}
else if ( t.isUpSlope( next ) )
{
return rl(
RABBIT_RISING_RIGHT_START,
RABBIT_RISING_LEFT_START
);
}
else if ( t.isDownSlope( t.blockBelowNext() ) )
{
if ( Blocking.blockerAt( t.world, nextX, t.rabbit.y + 1 ) )
{
return rl(
RABBIT_TURNING_RIGHT_TO_LEFT,
RABBIT_TURNING_LEFT_TO_RIGHT
);
}
else
{
return rl(
RABBIT_LOWERING_RIGHT_START,
RABBIT_LOWERING_LEFT_START
);
}
}
else
{
return rl(
RABBIT_WALKING_RIGHT,
RABBIT_WALKING_LEFT
);
}
}
}
private State rl( State rightState, State leftState )
{
return t.rl( rightState, leftState );
}
}
@Override
public boolean checkTriggered( Rabbit rabbit, World world )
{
return false; // To avoid cancelling other behaviours, return false
}
@Override
public State newState( BehaviourTools t, boolean triggered )
{
return new StateCalc( t ).newState();
}
@Override
@SuppressWarnings("fallthrough")
public boolean behave( World world, Rabbit rabbit, State state )
{
switch ( state )
{
case RABBIT_WALKING_LEFT:
{
--rabbit.x;
rabbit.onSlope = false;
return true;
}
case RABBIT_WALKING_RIGHT:
{
++rabbit.x;
rabbit.onSlope = false;
return true;
}
case RABBIT_LOWERING_LEFT_END:
{
--rabbit.x;
rabbit.onSlope = false;
return true;
}
case RABBIT_RISING_LEFT_START:
case RABBIT_LOWERING_AND_RISING_LEFT:
case RABBIT_RISING_AND_LOWERING_LEFT:
{
--rabbit.x;
rabbit.onSlope = true;
return true;
}
case RABBIT_LOWERING_RIGHT_END:
{
++rabbit.x;
rabbit.onSlope = false;
return true;
}
case RABBIT_RISING_RIGHT_START:
case RABBIT_LOWERING_AND_RISING_RIGHT:
case RABBIT_RISING_AND_LOWERING_RIGHT:
{
++rabbit.x;
rabbit.onSlope = true;
return true;
}
case RABBIT_RISING_LEFT_END:
{
--rabbit.y;
--rabbit.x;
rabbit.onSlope = false;
return true;
}
case RABBIT_RISING_LEFT_CONTINUE:
{
--rabbit.y;
--rabbit.x;
rabbit.onSlope = true;
return true;
}
case RABBIT_RISING_RIGHT_END:
{
--rabbit.y;
++rabbit.x;
rabbit.onSlope = false;
return true;
}
case RABBIT_RISING_RIGHT_CONTINUE:
{
--rabbit.y;
++rabbit.x;
rabbit.onSlope = true;
return true;
}
case RABBIT_LOWERING_LEFT_CONTINUE:
case RABBIT_LOWERING_LEFT_START:
{
++rabbit.y;
--rabbit.x;
rabbit.onSlope = true;
return true;
}
case RABBIT_LOWERING_RIGHT_CONTINUE:
case RABBIT_LOWERING_RIGHT_START:
{
++rabbit.y;
++rabbit.x;
rabbit.onSlope = true;
return true;
}
case RABBIT_TURNING_LEFT_TO_RIGHT:
rabbit.onSlope = false; // Intentional fall-through
case RABBIT_TURNING_LEFT_TO_RIGHT_RISING:
case RABBIT_TURNING_LEFT_TO_RIGHT_LOWERING:
{
rabbit.dir = RIGHT;
checkJumpOntoSlope( world, rabbit );
return true;
}
case RABBIT_TURNING_RIGHT_TO_LEFT:
rabbit.onSlope = false; // Intentional fall-through
case RABBIT_TURNING_RIGHT_TO_LEFT_RISING:
case RABBIT_TURNING_RIGHT_TO_LEFT_LOWERING:
{
rabbit.dir = LEFT;
checkJumpOntoSlope( world, rabbit );
return true;
}
default:
{
throw new AssertionError(
"Should have handled all states in Walking or before,"
+ " but we are in state " + state.name()
);
}
}
}
/**
* If we turn around near a slope, we jump onto it
*/
private void checkJumpOntoSlope( World world, Rabbit rabbit )
{
Block thisBlock = world.getBlockAt( rabbit.x, rabbit.y );
if ( isBridge( thisBlock ) )
{
Block aboveBlock = world.getBlockAt( rabbit.x, rabbit.y - 1 );
if ( rabbit.onSlope && isBridge( aboveBlock ) )
{
rabbit.y--;
}
else
{
rabbit.onSlope = true;
}
}
}
private boolean isBridge( Block block )
{
return (
block != null
&& (
block.shape == BRIDGE_UP_LEFT
|| block.shape == BRIDGE_UP_RIGHT
)
);
}
}