package rabbitescape.engine.behaviours;
import static rabbitescape.engine.ChangeDescription.State.*;
import static rabbitescape.engine.Block.Shape.*;
import java.util.Map;
import rabbitescape.engine.*;
import rabbitescape.engine.ChangeDescription.State;
public class Falling extends Behaviour
{
private static final int fatalHeight = 4;
private int heightFallen = 0;
private final Climbing climbing;
private final Brollychuting brollychuting;
public Falling( Climbing climbing, Brollychuting brollychuting )
{
this.climbing = climbing;
this.brollychuting = brollychuting;
}
public boolean isFallingToDeath()
{
return heightFallen > fatalHeight ;
}
@Override
public void cancel()
{
}
@Override
public boolean behave( World world, Rabbit rabbit, State state )
{
boolean handled = moveRabbit( world, rabbit, state );
if ( handled )
{
// Whenever we fall onto a slope, we are on top of it
Block thisBlock = world.getBlockAt( rabbit.x, rabbit.y );
if ( thisBlock != null && thisBlock.shape != FLAT )
{
rabbit.onSlope = true;
}
else
{
rabbit.onSlope = false;
}
}
return handled;
}
private boolean moveRabbit( World world, Rabbit rabbit, State state )
{
switch ( state )
{
case RABBIT_DYING_OF_FALLING:
case RABBIT_DYING_OF_FALLING_2:
case RABBIT_DYING_OF_FALLING_SLOPE_RISE_RIGHT_2:
case RABBIT_DYING_OF_FALLING_2_SLOPE_RISE_RIGHT_2:
case RABBIT_DYING_OF_FALLING_SLOPE_RISE_LEFT_2:
case RABBIT_DYING_OF_FALLING_2_SLOPE_RISE_LEFT_2:
{
world.changes.killRabbit( rabbit );
return true;
}
case RABBIT_FALLING:
case RABBIT_FALLING_ONTO_LOWER_RIGHT:
case RABBIT_FALLING_ONTO_LOWER_LEFT:
case RABBIT_FALLING_ONTO_RISE_RIGHT:
case RABBIT_FALLING_ONTO_RISE_LEFT:
case RABBIT_DYING_OF_FALLING_2_SLOPE_RISE_RIGHT:
case RABBIT_DYING_OF_FALLING_2_SLOPE_RISE_LEFT:
{
heightFallen += 2;
rabbit.y = rabbit.y + 2;
return true;
}
case RABBIT_DYING_OF_FALLING_SLOPE_RISE_RIGHT:
case RABBIT_DYING_OF_FALLING_SLOPE_RISE_LEFT:
case RABBIT_FALLING_1_TO_DEATH:
case RABBIT_FALLING_1:
case RABBIT_FALLING_1_ONTO_LOWER_RIGHT:
case RABBIT_FALLING_1_ONTO_LOWER_LEFT:
case RABBIT_FALLING_1_ONTO_RISE_RIGHT:
case RABBIT_FALLING_1_ONTO_RISE_LEFT:
{
heightFallen += 1;
rabbit.y = rabbit.y + 1;
return true;
}
default:
{
heightFallen = 0;
return false;
}
}
}
@Override
public boolean checkTriggered( Rabbit rabbit, World world )
{
if ( climbing.abilityActive
|| rabbit.state == RABBIT_DIGGING
|| brollychuting.hasBrolly() )
{
return false;
}
BehaviourTools t = new BehaviourTools( rabbit, world );
//noinspection RedundantIfStatement
if ( t.isFlat( t.blockBelow() ) )
{
return false;
}
if (
rabbit.onSlope
&& !t.blockHereJustRemoved()
)
{
return false;
}
return true;
}
@Override
public State newState( BehaviourTools t, boolean triggered )
{
if ( RABBIT_DYING_OF_FALLING_SLOPE_RISE_LEFT == t.rabbit.state )
{ // part 2 of animation always comes next
return RABBIT_DYING_OF_FALLING_SLOPE_RISE_LEFT_2;
}
if ( RABBIT_DYING_OF_FALLING_2_SLOPE_RISE_LEFT == t.rabbit.state )
{ // part 2 of animation always comes next
return RABBIT_DYING_OF_FALLING_2_SLOPE_RISE_LEFT_2;
}
if ( RABBIT_DYING_OF_FALLING_SLOPE_RISE_RIGHT == t.rabbit.state )
{ // part 2 of animation always comes next
return RABBIT_DYING_OF_FALLING_SLOPE_RISE_RIGHT_2;
}
if ( RABBIT_DYING_OF_FALLING_2_SLOPE_RISE_RIGHT == t.rabbit.state )
{
return RABBIT_DYING_OF_FALLING_2_SLOPE_RISE_RIGHT_2;
}
if ( !triggered )
{
if ( heightFallen > fatalHeight )
{
if ( heightFallen % 2 == 0 )
{
return RABBIT_DYING_OF_FALLING;
}
else
{
return RABBIT_DYING_OF_FALLING_2;
}
}
return null;
}
if (
( heightFallen + 1 > fatalHeight ) // Going to die
&& ( // during step
t.isFlat( t.block2Below() )
|| t.blockBelow() != null
)
)
{
if( BehaviourTools.isRightRiseSlope( t.blockBelow() ) )
{
return RABBIT_DYING_OF_FALLING_SLOPE_RISE_RIGHT;
}
else if( BehaviourTools.isLeftRiseSlope( t.blockBelow() ) )
{
return RABBIT_DYING_OF_FALLING_SLOPE_RISE_LEFT;
}
else
{
return State.RABBIT_FALLING_1_TO_DEATH;
}
}
else
{
Block below = t.blockBelow();
if ( below != null )
{
if ( t.isUpSlope( below ) )
{
return t.rl(
RABBIT_FALLING_1_ONTO_RISE_RIGHT,
RABBIT_FALLING_1_ONTO_RISE_LEFT
);
}
else // Must be a slope in the opposite direction
{
return t.rl(
RABBIT_FALLING_1_ONTO_LOWER_RIGHT,
RABBIT_FALLING_1_ONTO_LOWER_LEFT
);
}
}
Block twoBelow = t.block2Below();
if ( twoBelow != null )
{
if ( heightFallen + 1 > fatalHeight
&& BehaviourTools.isRightRiseSlope( twoBelow ) )
{
return RABBIT_DYING_OF_FALLING_2_SLOPE_RISE_RIGHT;
}
if ( heightFallen + 1 > fatalHeight
&& BehaviourTools.isLeftRiseSlope( twoBelow ) )
{
return RABBIT_DYING_OF_FALLING_2_SLOPE_RISE_LEFT;
}
if ( t.isFlat( twoBelow ) ) // Flat block
{
return State.RABBIT_FALLING_1;
}
if( t.isUpSlope( twoBelow ) )
{
return t.rl(
RABBIT_FALLING_ONTO_RISE_RIGHT,
RABBIT_FALLING_ONTO_RISE_LEFT
);
}
else
{
return t.rl(
RABBIT_FALLING_ONTO_LOWER_RIGHT,
RABBIT_FALLING_ONTO_LOWER_LEFT
);
}
}
else
{
return State.RABBIT_FALLING;
}
}
}
@Override
public void saveState( Map<String, String> saveState )
{
BehaviourState.addToStateIfGtZero(
saveState, "Falling.heightFallen", heightFallen
);
}
@Override
public void restoreFromState( Map<String, String> saveState )
{
heightFallen = BehaviourState.restoreFromState(
saveState, "Falling.heightFallen", heightFallen
);
}
}