class CQEnemy : Movable { var direction = -1 var allowReverse = true override fun begin() { speed -= 2 super.begin() } override fun myTurn() { val player = PlayDirector.instance.player var newDir = direction // If we are heading directly towards or away from the player, then do not try left or right if (player.actor.y == actor.y && direction % 2 == 0) { // When heading into an East/West cul-de-sac, then get stuck. This makes it easy to trap // the nasties, but can also make life tricky for the player in some circumstances. allowReverse = false newDir = if (player.actor.x > actor.x) EAST else WEST } else if (player.actor.x == actor.x && direction % 2 == 1) { newDir = if (player.actor.y > actor.y) NORTH else SOUTH } else { // Try not to move forwards again, so look LEFT first newDir = (direction + 1) % 4 // If we are heading away, then try RIGHT first if (headingAway( newDir )) { newDir = (newDir + 2) % 4 } if (! canMove( newDir ) ) { // Couldn't turn one way, so lets try turning the other way. // This will be away from the player, but not in a straight line. newDir = (newDir + 2) % 4 if (! canMove( newDir ) ) { // We couldn't turn left, or right, so lets try straight ahead (keep direction unchanged). if ( canMove( direction ) ) { newDir = direction } else { // Ok, so we've tried left, right and straight on. If we are in an E/W cul-de-sac, // then do NOT try to move backwards. if ( (!allowReverse) && (direction == EAST || direction == WEST) && isCulDeSac() ) { // Do nothing } else { // Reverse direction newDir = (direction + 2) % 4 } } } } } if (canMove( newDir )) { direction = newDir allowReverse = true move( direction ) } } fun isCulDeSac() : boolean { val up = lookNorth() if (up.isEmpty() || up.item() is CQEnemy) return false val down = lookSouth() if (down.isEmpty() || down.item() is CQEnemy) return false return true } override fun move( direction : int ) { actor.event( "move_" + Item.directionAbbreviation(direction) ) val there = look( direction ) if (there.item() is Player) { there.item().kill() } if (PlayDirector.instance.mainView.visible( actor ) ) { actor.event( "move" + direction ) } super.move(direction) } fun headingAway( direction : int ) : boolean { val player = PlayDirector.instance.player val dx = Item.getDeltaX( direction ) val dy = Item.getDeltaY( direction ) val tx = player.actor.x - actor.x val ty = player.actor.y - actor.y if (dx * tx > 0) return false if (dy * ty > 0) return false return true } fun canMove( direction : int ) : boolean { val foo = look( direction ) return foo.isEmpty() || foo.isPlayer() } override fun kill() { val list = PlayDirector.instance.extraStage.findRolesByClass( CQSpawn ) val spawn = list[ Rand.randomInt( list.size() ) ] if (spawn != null && spawn.square.isEmpty() ) { warpTo( spawn.square ) replaceAction( createAction() ) } else { actor.die() } } }