package rabbitescape.engine.behaviours;
import static rabbitescape.engine.ChangeDescription.State.*;
import static rabbitescape.engine.Token.Type.*;
import static rabbitescape.engine.Block.Material.*;
import static rabbitescape.engine.Block.Shape.*;
import java.util.Map;
import rabbitescape.engine.*;
import rabbitescape.engine.ChangeDescription.State;
public class Bridging extends Behaviour
{
enum BridgeType
{
ALONG,
UP,
DOWN_UP
}
private int smallSteps = 0;
private int bigSteps = 0;
private BridgeType bridgeType = BridgeType.ALONG;
@Override
public void cancel()
{
bigSteps = 0;
smallSteps = 0;
}
@Override
public boolean checkTriggered( Rabbit rabbit, World world )
{
nextStep();
if ( bigSteps <= 0 )
// Only pick up a token if we've finished, and we can bridge
{
BehaviourTools t = new BehaviourTools( rabbit, world );
State possibleState = bridgingState( t, 3, 3, bridgeType );
if ( possibleState != null ) // Only pick up if we can bridge
{
return t.pickUpToken( bridge );
}
}
return false;
}
@Override
public State newState( BehaviourTools t, boolean triggered )
{
if ( triggered )
{
smallSteps = 3;
bigSteps = 3;
}
State ret = bridgingState( t, bigSteps, smallSteps, bridgeType );
if ( ret == null )
{
bigSteps = 0;
}
if ( bigSteps <= 0 )
{
smallSteps = 0;
return null; // Finished bridging
}
return ret;
}
private static State bridgingState(
BehaviourTools t,
int bs,
int ss,
BridgeType bt
)
{
Block hereBlock = t.blockHere();
Rabbit rabbit = t.rabbit;
World world = t.world;
if ( startingIntoToWall( world, rabbit, bs ) )
{
return stateIntoWall( t, rabbit, world, ss );
}
boolean slopeUp = isSlopeUp( rabbit, hereBlock );
int nx = nextX( rabbit );
int ny = nextY( rabbit, slopeUp );
Block nextBlock = world.getBlockAt( nx, ny );
Block belowNextBlock = world.getBlockAt( nx, rabbit.y );
Block twoAboveHereBlock = world.getBlockAt( rabbit.x, rabbit.y - 2 );
Block aboveNextBlock = world.getBlockAt( nx, ny - 1 );
if (
(
// Something in the way
nextBlock != null
&& nextBlock.riseDir() != rabbit.dir
) || (
Blocking.blockerAt( t.world, nx, ny )
) || (
// Clip land
belowNextBlock != null
&& belowNextBlock.riseDir() != rabbit.dir
) || (
// Bang head next
aboveNextBlock != null
&& BehaviourTools.isSolid( aboveNextBlock )
) || (
// Bang head here, mid-build
bs < 3
&& BehaviourTools.s_isFlat( twoAboveHereBlock )
)
)
{
return null; // Stop bridging
}
boolean slopeDown = (
( hereBlock != null )
&& ( hereBlock.riseDir() == Direction.opposite( rabbit.dir ) )
);
switch( ss )
{
case 3:
{
if ( slopeUp )
{
return t.rl(
RABBIT_BRIDGING_UP_RIGHT_1,
RABBIT_BRIDGING_UP_LEFT_1
);
}
else if ( slopeDown )
{
return t.rl(
RABBIT_BRIDGING_DOWN_UP_RIGHT_1,
RABBIT_BRIDGING_DOWN_UP_LEFT_1
);
}
else
{
return t.rl(
RABBIT_BRIDGING_RIGHT_1,
RABBIT_BRIDGING_LEFT_1
);
}
}
case 2:
{
switch( bt )
{
case ALONG:
{
return t.rl(
RABBIT_BRIDGING_RIGHT_2,
RABBIT_BRIDGING_LEFT_2
);
}
case UP:
{
return t.rl(
RABBIT_BRIDGING_UP_RIGHT_2,
RABBIT_BRIDGING_UP_LEFT_2
);
}
case DOWN_UP:
{
return t.rl(
RABBIT_BRIDGING_DOWN_UP_RIGHT_2,
RABBIT_BRIDGING_DOWN_UP_LEFT_2
);
}
default:
{
throw new AssertionError( "Unexpected bridge type: " + bt );
}
}
}
case 1:
{
switch( bt )
{
case ALONG:
{
return t.rl(
RABBIT_BRIDGING_RIGHT_3,
RABBIT_BRIDGING_LEFT_3
);
}
case UP:
{
return t.rl(
RABBIT_BRIDGING_UP_RIGHT_3,
RABBIT_BRIDGING_UP_LEFT_3
);
}
case DOWN_UP:
{
return t.rl(
RABBIT_BRIDGING_DOWN_UP_RIGHT_3,
RABBIT_BRIDGING_DOWN_UP_LEFT_3
);
}
default:
{
throw new AssertionError( "Unexpected bridge type: " + bt );
}
}
}
default:
{
return null;
}
}
}
private static State stateIntoWall(
BehaviourTools t, Rabbit rabbit, World world, int ss )
{
Block thisBlock = world.getBlockAt( rabbit.x, rabbit.y );
boolean slopeUp = isSlopeUp( rabbit, thisBlock );
int bx = behindX( rabbit );
int ny = nextY( rabbit, slopeUp );
if ( isSlope( thisBlock ) && world.getBlockAt( bx, ny ) == null )
{
return null;
}
switch( ss )
{
case 3:
{
if ( isSlope( thisBlock ) )
{
return t.rl(
RABBIT_BRIDGING_IN_CORNER_UP_RIGHT_1,
RABBIT_BRIDGING_IN_CORNER_UP_LEFT_1
);
}
else
{
return t.rl(
RABBIT_BRIDGING_IN_CORNER_RIGHT_1,
RABBIT_BRIDGING_IN_CORNER_LEFT_1
);
}
}
case 2:
{
if ( isSlope( thisBlock ) )
{
return t.rl(
RABBIT_BRIDGING_IN_CORNER_UP_RIGHT_2,
RABBIT_BRIDGING_IN_CORNER_UP_LEFT_2
);
}
else
{
return t.rl(
RABBIT_BRIDGING_IN_CORNER_RIGHT_2,
RABBIT_BRIDGING_IN_CORNER_LEFT_2
);
}
}
case 1:
{
if ( isSlope( thisBlock ) )
{
return t.rl(
RABBIT_BRIDGING_IN_CORNER_UP_RIGHT_3,
RABBIT_BRIDGING_IN_CORNER_UP_LEFT_3
);
}
else
{
return t.rl(
RABBIT_BRIDGING_IN_CORNER_RIGHT_3,
RABBIT_BRIDGING_IN_CORNER_LEFT_3
);
}
}
default:
{
return null;
}
}
}
private static boolean startingIntoToWall(
World world,
Rabbit rabbit,
int bs
)
{
Block hereBlock = world.getBlockAt( rabbit.x, rabbit.y );
boolean slopeUp = isSlopeUp( rabbit, hereBlock );
int nx = nextX( rabbit );
int ny = nextY( rabbit, slopeUp );
Block nextBlock = world.getBlockAt( nx, ny );
return (
bs == 3
)
&&
(
nextBlock != null
&&
(
nextBlock.riseDir() != rabbit.dir
|| nextBlock.shape == FLAT
)
);
}
private static boolean isSlopeUp( Rabbit rabbit, Block hereBlock )
{
return ( hereBlock != null )
&& ( hereBlock.riseDir() == rabbit.dir );
}
private static int nextY( Rabbit rabbit, boolean slopeUp )
{
int ret = rabbit.y;
ret += slopeUp ? -1 : 0;
return ret;
}
private static int nextX( Rabbit rabbit )
{
int ret = rabbit.x;
ret += rabbit.dir == Direction.RIGHT ? 1 : -1;
return ret;
}
private static int behindX( Rabbit rabbit )
{
int ret = rabbit.x;
ret += rabbit.dir == Direction.RIGHT ? -1 : 1;
return ret;
}
private void nextStep()
{
--smallSteps;
if ( smallSteps <= 0 )
{
--bigSteps;
smallSteps = 3;
}
}
private static boolean isSlope( Block thisBlock )
{
return ( thisBlock != null && thisBlock.shape != FLAT );
}
@Override
public boolean behave( World world, Rabbit rabbit, State state )
{
boolean handled = moveRabbit( world, rabbit, state );
if ( handled )
{
// If we're bridging, we're on a slope
rabbit.onSlope = true;
}
return handled;
}
private boolean moveRabbit( World world, Rabbit rabbit, State state )
{
switch ( state )
{
case RABBIT_BRIDGING_RIGHT_1:
case RABBIT_BRIDGING_RIGHT_2:
case RABBIT_BRIDGING_LEFT_1:
case RABBIT_BRIDGING_LEFT_2:
{
bridgeType = BridgeType.ALONG;
return true;
}
case RABBIT_BRIDGING_UP_RIGHT_1:
case RABBIT_BRIDGING_UP_RIGHT_2:
case RABBIT_BRIDGING_UP_LEFT_1:
case RABBIT_BRIDGING_UP_LEFT_2:
{
bridgeType = BridgeType.UP;
return true;
}
case RABBIT_BRIDGING_DOWN_UP_RIGHT_1:
case RABBIT_BRIDGING_DOWN_UP_RIGHT_2:
case RABBIT_BRIDGING_DOWN_UP_LEFT_1:
case RABBIT_BRIDGING_DOWN_UP_LEFT_2:
{
bridgeType = BridgeType.DOWN_UP;
return true;
}
case RABBIT_BRIDGING_IN_CORNER_RIGHT_1:
case RABBIT_BRIDGING_IN_CORNER_LEFT_1:
case RABBIT_BRIDGING_IN_CORNER_RIGHT_2:
case RABBIT_BRIDGING_IN_CORNER_LEFT_2:
case RABBIT_BRIDGING_IN_CORNER_UP_RIGHT_1:
case RABBIT_BRIDGING_IN_CORNER_UP_LEFT_1:
case RABBIT_BRIDGING_IN_CORNER_UP_RIGHT_2:
case RABBIT_BRIDGING_IN_CORNER_UP_LEFT_2:
{
bridgeType = BridgeType.ALONG;
return true;
}
case RABBIT_BRIDGING_RIGHT_3:
case RABBIT_BRIDGING_DOWN_UP_RIGHT_3:
{
rabbit.x++;
world.changes.addBlock(
new Block(
rabbit.x,
rabbit.y,
EARTH,
BRIDGE_UP_RIGHT,
0
)
);
return true;
}
case RABBIT_BRIDGING_LEFT_3:
case RABBIT_BRIDGING_DOWN_UP_LEFT_3:
{
rabbit.x--;
world.changes.addBlock(
new Block(
rabbit.x,
rabbit.y,
EARTH,
BRIDGE_UP_LEFT,
0
)
);
return true;
}
case RABBIT_BRIDGING_UP_RIGHT_3:
{
rabbit.x++;
rabbit.y--;
world.changes.addBlock(
new Block(
rabbit.x,
rabbit.y,
EARTH,
BRIDGE_UP_RIGHT,
0
)
);
return true;
}
case RABBIT_BRIDGING_UP_LEFT_3:
{
rabbit.x--;
rabbit.y--;
world.changes.addBlock(
new Block(
rabbit.x,
rabbit.y,
EARTH,
BRIDGE_UP_LEFT,
0
)
);
return true;
}
case RABBIT_BRIDGING_IN_CORNER_RIGHT_3:
{
rabbit.onSlope = true;
world.changes.addBlock(
new Block(
rabbit.x,
rabbit.y,
EARTH,
BRIDGE_UP_RIGHT,
0
)
);
return true;
}
case RABBIT_BRIDGING_IN_CORNER_LEFT_3:
{
rabbit.onSlope = true;
world.changes.addBlock(
new Block(
rabbit.x,
rabbit.y,
EARTH,
BRIDGE_UP_LEFT,
0
)
);
return true;
}
case RABBIT_BRIDGING_IN_CORNER_UP_RIGHT_3:
{
rabbit.onSlope = true;
rabbit.y--;
world.changes.addBlock(
new Block(
rabbit.x,
rabbit.y,
EARTH,
BRIDGE_UP_RIGHT,
0
)
);
return true;
}
case RABBIT_BRIDGING_IN_CORNER_UP_LEFT_3:
{
rabbit.onSlope = true;
rabbit.y--;
world.changes.addBlock(
new Block(
rabbit.x,
rabbit.y,
EARTH,
BRIDGE_UP_LEFT,
0
)
);
return true;
}
default:
{
return false;
}
}
}
@Override
public void saveState( Map<String, String> saveState )
{
BehaviourState.addToStateIfNotDefault(
saveState,
"Bridging.bridgeType",
bridgeType.toString(),
BridgeType.ALONG.toString()
);
BehaviourState.addToStateIfGtZero(
saveState, "Bridging.bigSteps", bigSteps
);
BehaviourState.addToStateIfGtZero(
saveState, "Bridging.smallSteps", smallSteps
);
}
@Override
public void restoreFromState( Map<String, String> saveState )
{
bridgeType = BridgeType.valueOf(
BehaviourState.restoreFromState(
saveState, "Bridging.bridgeType", bridgeType.toString()
)
);
bigSteps = BehaviourState.restoreFromState(
saveState, "Bridging.bigSteps", bigSteps
);
smallSteps = BehaviourState.restoreFromState(
saveState, "Bridging.smallSteps", smallSteps
);
if ( smallSteps > 0 )
{
++smallSteps;
}
}
}