Exit Full View

Games Cupboard / gamescupboard-client / src / commonMain / kotlin / uk / co / nickthecoder / gamescupboard / client / view / GameObjectView.kt

package uk.co.nickthecoder.gamescupboard.client.view

import DragObject
import MoveObject
import ChangeZOrder
import RunCommand
import com.soywiz.klock.milliseconds
import com.soywiz.korge.input.mouse
import com.soywiz.korge.tween.get
import com.soywiz.korge.view.Container
import com.soywiz.korma.geom.Point
import com.soywiz.korma.interpolation.Easing
import uk.co.nickthecoder.gamescupboard.client.*
import uk.co.nickthecoder.gamescupboard.common.CommandPrototype
import uk.co.nickthecoder.gamescupboard.common.FlippableImageObject
import uk.co.nickthecoder.gamescupboard.common.GameObject
import uk.co.nickthecoder.gamescupboard.common.SpecialArea

/**
 * The visual representation of a [GameObject] on the client.
 *
 *
 */
abstract class GameObjectView(val id: Int) : Container() {

    abstract fun isTouching(point: Point): Boolean

    /**
     * Names must either be blank, or unique.
     * See GamesCupboardClient.createGameObjectView for when this is set.
     */
    var objectName: String = ""

    /**
     * Set when any player is dragging this object. If another player is dragging this,
     * then the local player cannot also drag it.
     */
    var isDragging = false

    /**
     * Most game objects are draggable. Background images, and other "decoration" aren't.
     */
    var isDraggable = false

    /**
     * If this is set to true, the [onDoubleClick] should perform the double click action.
     * I deliberately did not call this isClickable, because at a later date, there may be other actions
     * other than double-clicking. e.g. right click for a context menu.
     *
     * Currently, [FlippableImageObjectView] and [BinView] are actionable.
     */
    var isActionable = false

    /**
     * This is primarily for card games, where only one player can see the cards in their hand.
     * Rather than trying to fit *everyone's* hand on screen, there is an area on the screen
     * where everyone's "private" cards are placed.
     * You can only see your own cards.
     *
     * When a card is dropped into a private [SpecialArea] (where `isPublic==false`), it is turned face up
     * but invisible to all others.
     *
     * NOTE. At this point, [FlippableImageObject.isFaceUp] == false (despite it being face up for
     * one player).
     * This is so that there's no possibility of it being seen by others when it is dragging it out again.
     *
     * When the "owner" is dragging it out of the private [SpecialArea], the [DragObject] message
     * has [DragObject.forceFaceDown] = true.
     *
     * While dragging over a public [SpecialArea] (i.e. the main part of the card table),
     * the card still appears face up, but with a red tint (only for the player dragging it).
     * This is a warning that releasing the mouse will reveal the card.
     * The red tint is not transmitted to the server, it is only on the client.
     *
     * When the mouse is released (to end the drag operation), if it lands in a public [SpecialArea],
     * it is turned face up, for all to see.
     *
     * However, if it lands outside a [SpecialArea], it is turned face down. This is handy when passing cards to other
     * players (e.g. the card game Hearts).
     *
     * It can be tricky to move a card long distances on computers with a button-less trackpad.
     * In this case, the player should double-click the card while in the private area. Then drag it
     * (possibly in two or move spurts), and then turn it over again by double-clicking again.
     */
    var privateToPlayerId: Int? = null

    var commandPrototype: CommandPrototype? = null
        set(v) {
            field = v
            if (v != null) {
                mouse.click {
                    if (v.isComplete) {
                        RunCommand(v.commandName, v.parameters).send()
                    } else {
                        gamesCupboardClient.chatInput.commandPrototype(v)
                    }
                }
            }
        }


    fun moveMessage() =
        MoveObject(id, gamesCupboardClient.mirroredX(x), gamesCupboardClient.mirroredY(y), ChangeZOrder.NO_CHANGE)

    fun moveMessage(changeZOrder: ChangeZOrder) =
        MoveObject(id, gamesCupboardClient.mirroredX(x), gamesCupboardClient.mirroredY(y), changeZOrder)

    open fun defaultScale() = 1.0

    open fun onDoubleClick(playingArea: PlayingArea) {}

    open fun highlight() {
        launchTweenThen(
            this::scale[highlightScale],
            easing = Easing.EASE_IN_OUT,
            time = highlightPeriod.milliseconds
        ) {
            launchTween(
                this::scale[1.0], easing = Easing.EASE_IN_OUT, time = highlightPeriod.milliseconds
            )
        }
    }
}