import uk.co.nickthecoder.glok.event.Key
import uk.co.nickthecoder.glok.property.boilerplate.intProperty
import uk.co.nickthecoder.kyd.Actor
import uk.co.nickthecoder.kyd.Ticks
import uk.co.nickthecoder.kyd.appearance.*
import uk.co.nickthecoder.kyd.nodes.PlayActView
/**
* Checks for arrow keys, and moves in that direction.
* If the path is clear, we can walk freely.
*
* If the path is blocked by [Soil], we use up a [blasts] to destroy the soil.
*
* We can also collect [Fuel] and [Dynamite]. We can also enter our [Ship], but only if we
* have collected [Fuel].
*
* We cannot move over any other objects (including [Monster]s.
*/
class Player : Item(), Killable {
/**
* See [PlayDirector.blastsProperty]
*/
val blastsProperty by intProperty(0)
var blasts by blastsProperty
private var idle = true
private lateinit var idleAnimation: FlipBook
private lateinit var walkingAnimation: FlipBook
private lateinit var blastingAnimation: FlipBook
override val isEmpty get() = true
override fun onEnteredStage(actor: Actor) {
super.onEnteredStage(actor)
PlayDirector.instance.registerPlayer(actor, this)
val role = actor.role ?: return
val a = role.findAppearance("a")
val b = role.findAppearance("b")
idleAnimation = flipBook {
page(a, playerIdleFrameTime)
page(b, playerIdleFrameTime)
}
walkingAnimation = flipBook {
repetitions = 1
page(a, playerWalkTime)
onFinished {
idle = true
idleAnimation.applyToActor(actor)
}
}
blastingAnimation = flipBook { // The same timing as Soil's blast animation.
repetitions = 3
val pageCount = 2
page(a, soilBlastTime / repetitions / pageCount)
page(b, soilBlastTime / repetitions / pageCount)
onFinished {
idle = true
idleAnimation.applyToActor(actor)
}
}
idleAnimation.applyToActor(actor)
}
override fun tick(actor: Actor, seconds: Float) {
// Tick the animation if there is one.
(actor.appearance as? Ticks)?.tick(actor, seconds)
if (idle) {
val view = PlayActView.instance
var dx = 0
var dy = 0
if (view.isKeyDown(Key.LEFT)) {
dx = - 1
} else if (view.isKeyDown(Key.RIGHT)) {
dx = 1
} else if (view.isKeyDown(Key.UP)) {
dy = 1
} else if (view.isKeyDown(Key.DOWN)) {
dy = - 1
}
if (dx != 0 || dy != 0) {
// Have we collected something (Fuel or Dynamite).
val otherActor = look(dx, dy)
(otherActor?.behaviour as? Collectable)?.collect(otherActor)
(otherActor?.behaviour as? Ship)?.let { ship ->
if (PlayDirector.instance.fueled) {
ship.blastOff(otherActor)
PlayDirector.instance.blastOff(otherActor)
actor.parent.removeActor(actor)
return
}
}
if (move(actor, dx, dy)) {
walking(actor)
} else {
tryBlast(actor, dx, dy)
}
}
}
}
/**
* Oh dear, we've been hit by a [Rock], or eaten by a [Monster]
*/
override fun killedBy(killer: Actor, victim: Actor) {
victim.parent.removeActor(victim)
PlayDirector.instance.playerDied()
}
private fun tryBlast(actor: Actor, dx: Int, dy: Int): Boolean {
if (blasts > 0) {
val otherActor = look(dx, dy)
if (otherActor.isSoil()) {
(otherActor?.behaviour as? Soil)?.let { soil ->
soil.blast(otherActor)
blasts --
idle = false
blastingAnimation.applyToActor(actor)
return true
}
}
}
return false
}
private fun walking(actor: Actor) {
idle = false
walkingAnimation.applyToActor(actor)
}
}