Exit Full View

Games Cupboard / gamescupboard-server / src / main / kotlin / uk / co / nickthecoder / gamescupboard / server / GameVariation.kt

package uk.co.nickthecoder.gamescupboard.server

import uk.co.nickthecoder.gamescupboard.common.*
import uk.co.nickthecoder.gamescupboard.server.commands.Command

data class GameVariation(
    /**
     * A unique identifier.
     * Only alpha-numerics (no spaces. camelCase).
     */
    val name: String,
    /**
     * A human friendly label for this variation. Usually very similar to [name].
     */
    val label: String,

    val minPlayers: Int,

    val maxPlayers: Int,

    /**
     * The background color of the playing area (or blank if a background is not required).
     * This isn't used at present, but may be useful if/when we can pan the playing area.
     */
    val bgColor: String = "",

    /**
     * Bitmaps containing many images in a grid.
     */
    val grids: List<Grid> = emptyList(),

    /**
     * The objects which make up the background.
     * These should NOT be draggable.
     *
     * Use negative numbers for the ids, so that [playingObjects] can start at zero.
     */
    val backgroundObjects: List<GameObject>,

    /**
     * The objects in the main playing area. Most objects will be draggable.
     */
    val playingObjects: List<GameObject>,

    /**
     * A layer above [backgroundObjects] and [playingObjects].
     * These should NOT be draggable.
     *
     * Use negative numbers for the ids, so that they never interfere with [playingObjects].
     */
    val foregroundObjects: List<GameObject> = emptyList(),

    /**
     * Both "private" and "public" areas, where cards are automatically turned over.
     *
     */
    val specialAreas: List<SpecialArea> = emptyList(),

    /**
     * See [SpecialPoint]. First used to mark the point of the deck of cards.
     */
    val specialPoints: List<SpecialPoint> = emptyList(),

    /**
     * Commands specific to this [GameVariation].
     * For example, card games have a "deal" and "take" commands, which moves cards from
     * the deck to the player's hand (private SpecialArea).
     */
    val commands: List<Command> = emptyList(),

    /**
     * Each [CommandPrototype] becomes a Button in the Toolbar.
     * If [CommandPrototype.isComplete], then clicking the button will run the command.
     * Otherwise, clicking the button will just enter the command into the ChatInput,
     * and let the player complete the command.
     *
     * e.g. Card games have a ":deal" prototype, where the player then types the number of card to deal.
     */
    val commandPrototypes: List<CommandPrototype> = emptyList(),

    val draggableAvatars: Boolean = true,
    val avatarPositions: AvatarPositions,

    /**
     * The rules will appear in the dock.
     * Text will flow to fit the width of the dockable.
     * A single new line character is treated the same as any white space
     * (i.e. it does not force a new line in the output).
     * To force a new line, use two new line characters.
     * And if you want a blank line, then use three new line characters.
     */
    val rules: String = "",

    val options: List<VariationOption> = emptyList(),

    val buttons: List<CommandButton> = emptyList(),

    val mirrorX: Int = 0,
    /**
     * If not zero, then half of the players will see the board the other way up.
     * e.g. In chess, draughts etc. both players will see their pieces at the bottom of the board.
     * Currently, this is either 0, or 300, as there is no mechanism for only *some* objects/areas to be flipped,
     * so it only makes sense for a *fully* symmetric view.
     */
    val mirrorY: Int = 0,

    val playerColors: List<String> = listOf(red, blue, orange, yellow, green, magenta),

    val scoreSheetHasBidColumn: Boolean = false

) {
    fun differentPlayingObjects(playingObjects: List<GameObject>) = GameVariation(
        name, label, minPlayers, maxPlayers, bgColor,
        grids = grids,
        backgroundObjects = backgroundObjects,
        playingObjects = playingObjects,
        foregroundObjects = foregroundObjects,
        specialAreas = specialAreas,
        specialPoints = specialPoints,
        commands = commands,
        commandPrototypes = commandPrototypes,
        draggableAvatars = draggableAvatars,
        avatarPositions = avatarPositions,
        rules = rules,
        options = options,
        buttons = buttons,
        mirrorX = mirrorX,
        mirrorY = mirrorY,
        playerColors = playerColors,
        scoreSheetHasBidColumn = scoreSheetHasBidColumn
    )

    fun extraPlayingObjects(extras: List<GameObject>) = differentPlayingObjects(playingObjects + extras)

    fun playerColor(id: Int, isSpectator: Boolean) =
        if (isSpectator) spectatorColor else playerColors[(id + playerColors.size - 1) % playerColors.size]

    companion object {
        const val spectatorColor = "#cec"

        const val red = "#c6493e"
        const val blue = "#465bc9"
        const val orange = "#c82"
        const val yellow = "#e4ea50"
        const val green = "#282"
        const val magenta = "#828"

        const val chessBlack = "#6e645b"
        const val chessWhite = "#efd5ba"
    }
}

class VariationOption(val name: String, val label: String, val build: (GameVariation) -> GameVariation)