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)