class Movement( val item : Movable, val dx : int, val dy : int, val speed : int ) : AbstractAction { var moved = 0 val direction = if ( dx == 1 && dy == 0 ) { 0 } else if ( dx == 0 && dy == 1 ) { 1 } else if ( dx == -1 && dy == 0 ) { 2 } else if ( dx == 0 && dy == -1 ) { 3 } else { -1 } var fromSquare = item.square var toSquare = fromSquare.neighbour( dx, dy ) init { item.movement = this if ( toSquare.entrant != null ) { println( "WARNING Two items entering " + toSquare + " and " + item ) } toSquare.entrant = item if ( item is Compound ) { for ( m in (item as Compound).parts() ) { m.square.neighbour( dx, dy ).entrant = m } } } override fun begin() : boolean { moved = 0 return false } fun finish() { item.actor.x += dx * (item.gridSize() - moved) item.actor.y += dy * (item.gridSize() - moved) } fun cancel() { toSquare.entrant = null } override fun act() : boolean { val gridSize = item.gridSize() val halfWay = gridSize ~/ 2 if ( moved < halfWay && moved + speed >= halfWay ) { // Hit the half way mark! toSquare.invading( this ) if ( item is Compound ) { for ( part in (item as Compound).parts() ) { part.square.neighbour( dx, dy ).invading( this ) } } } item.actor.x += dx * speed item.actor.y += dy * speed moved += speed if ( moved >= gridSize ) { // Overshot? Move back a bit if (moved > gridSize ) { item.actor.x -= dx * (moved - gridSize ) item.actor.y -= dy * (moved - gridSize ) } // Finalise the movement item.movement = null toSquare.entrant = null if ( item is Compound ) { for ( m in (item as Compound).parts() ) { m.square.neighbour( dx, dy ).entrant = null } } var invadedResult = true if ( item is Compound ) { for ( edge in (item as Compound).edges( direction ) ) { if ( ! edge.square.neighbour( dx, dy ).invaded( this ) ) { invadedResult = false } } } else { invadedResult = toSquare.invaded( this ) } if ( invadedResult ) { toSquare.addOccupant( item ) item.moved( this ) } return false } return false } override fun toString() = "Movement ${moved} of $item from $fromSquare to $toSquare" }