Exit Full View

Cavern Quest 2 / src / commonMain / kotlin / Item.kt

import uk.co.nickthecoder.glok.scene.Color
import uk.co.nickthecoder.glok.util.log
import uk.co.nickthecoder.kyd.Actor
import uk.co.nickthecoder.kyd.Behaviour
import uk.co.nickthecoder.kyd.util.Vector2

/**
 * The base-class for items in the [Grid].
 *
 * Using the grid, we can [look] at neighbouring places to check if they are empty etc.
 */
abstract class Item : Behaviour {

    /**
     * Can [Player] blast this? Only used by [Soil].
     * Note. soil.canBlast == `false` while it is being blasted.
     */
    open val canBlast: Boolean get() = false

    /**
     * Can [Player] / [Monster] / [Rock] move here?
     *
     * True for [Player] and any empty spots.
     * When [Monster] or [Rock] moves onto a [Player], the player dies.
     */
    open val isEmpty: Boolean get() = false

    /**
     * The references to our position in the [Grid].
     * (Note, I refer to these as _references_, not _indexes_, because they can be negative)
     */
    var gridX = 0
    var gridY = 0

    override fun onEnteredStage(actor: Actor) {
        val existing = PlayDirector.instance.grid.getAt(actor.position)
        if (existing != null) {
            log.error("Two items @ ${actor.position} : ${existing.behaviour} and $this")
            actor.appearance.tintIfAvailable = Color.RED
            existing.appearance.tintIfAvailable = Color.GREEN
        }
        val (x, y) = PlayDirector.instance.grid.putAt(actor.position, actor)
        gridX = x
        gridY = y
    }


    fun look(dx: Int, dy: Int): Actor? = PlayDirector.instance.grid[gridX + dx][gridY + dy]

    fun move(actor: Actor, dx: Int, dy: Int): Boolean {
        val grid = PlayDirector.instance.grid
        val otherActor = grid[gridX + dx][gridY + dy]
        if (otherActor.isEmpty()) {
            grid[gridX][gridY] = null
            actor.position += Vector2(dx * grid.gridSize, dy * grid.gridSize)
            gridX += dx
            gridY += dy
            grid[gridX][gridY] = actor
            return true
        }
        return false
    }
}

fun Actor?.isEmpty(): Boolean {
    if (this == null) return true
    val item = behaviour as? Item ?: return true
    return item.isEmpty
}

fun Actor?.isWall(): Boolean {
    if (this == null) return false
    return behaviour !is Monster
}

fun Actor?.isSoil(): Boolean {
    if (this == null) return false
    val item = behaviour as? Item ?: return false
    return item.canBlast
}