/** * The code common to Player and AutoPlayer */ class AbstractPlayer : AbstractBot { // When the player is in the center of the screen, then offsetX,Y will be 0,0 // The units are NOT pixels, but grid items. @Attribute var offsetX = 0.0 @Attribute var offsetY = 0.0 var scrollLeft : Input var scrollRight : Input var scrollUp : Input var scrollDown : Input var autoInstructions = "" // Can we pan around the map. Set to false by XORPlayer var enableOffset = true var awake = true override fun isPlayer() = true override fun begin() { super.begin() val inputs = Game.instance.resources.inputs scrollLeft = inputs.find( "scrollLeft" ) scrollRight = inputs.find( "scrollRight" ) scrollDown = inputs.find( "scrollDown" ) scrollUp = inputs.find( "scrollUp" ) } override fun canMove( direction : int, other : LookedAt ) : boolean { return super.canMove( direction, other ) || other.isDeadly() || other.collectable() || other.canPush( direction, speed, strength ) } override fun tick() { super.tick() if (awake) { if (enableOffset) { if (scrollLeft.isPressed()) { offsetX -= 0.1 } if (scrollRight.isPressed()) { offsetX += 0.1 } if (scrollUp.isPressed()) { offsetY += 0.1 } if (scrollDown.isPressed()) { offsetY -= 0.1 } } } } fun autoPlay() { if ( autoInstructions != "" ) { val letter = autoInstructions .substring(0,1) val lower = letter.toLowerCase() val wait = letter == letter.toUpperCase() // Feather doesn't have a switch statment yet :-( if ( lower == "u" || lower == "n" ) { autoMove( NORTH, wait ) } else if ( lower == "d" || lower == "s" ) { autoMove( SOUTH, wait ) } else if ( lower == "l" || lower == "w" ) { autoMove( WEST, wait ) } else if ( lower == "r" || lower == "e" ) { autoMove( EAST, wait ) } else if ( lower == "." ) { autoInstructions = autoInstructions .substring( 1 ) replaceAction( Delay( 0.5 ) then createAction() ) } } } fun autoMove( direction : int, wait : boolean ) { if ( tryToMove( direction ) || ! wait ) { autoInstructions = autoInstructions .substring( 1 ) } } fun tryToMove( direction : int ) : boolean { if (canMove( direction )) { makeMove( direction ) return true } return false } override fun invaded( movement : Movement ) : boolean { if ( movement.item.isDeadly() ) { kill() } else { println( "Warning. Player has been invaded by a non-deadly item ${movement}" ) } return true } static val partNames = listOf("head", "torso", "armL", "armR", "legL", "legR" ) override fun kill() { stopSpeaking() // Explode each body part becomes a projectile. See Shrapnel. // It is assumed that this actor has Costume events for each of these strings // with a Role of Shrapnel. for (partName in partNames) { val shrapnelA = actor.createChild( partName ) if ( shrapnelA != null ) { shrapnelA.stage = PlayDirector.instance.extraStage (shrapnelA.role as Shrapnel).explode( actor ) if ( partName == "head" ) { val text = actor.costume.chooseString( "dead" ) val speechA = actor.createChild( "speech" ) PlayDirector.instance.extraStage.add( speechA ) (speechA.role as Speech).speak( shrapnelA.role, text, 3, speechColor ) } } } actor.die() } fun wakeUp() { if ( !awake ) { awake = true // The delay prevents a rapid toggling between players at 60 times a second! replaceAction( EventsAction(actor, 6, "sleep1", "sleep2", "default" ) then Colorize( actor.color, 1, Color.white() ) then EventAction( actor, "wake" ) then createAction() ) } } fun fallAsleep() { if ( awake ) { actor.event( "sleep" ) awake = false replaceAction( EventsAction(actor, 6, "sleep0", "sleep1", "sleep2" ) then Colorize( actor.color, 1, Color( 0.8, 0.8, 0.8, 0.8 ) ) ) } } }