Skip to content

Commit

Permalink
Add win and lose conditions
Browse files Browse the repository at this point in the history
  • Loading branch information
adam-arold committed Jun 29, 2019
1 parent 07c5f05 commit b105517
Show file tree
Hide file tree
Showing 16 changed files with 175 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.hexworks.cavesofzircon.attributes

import org.hexworks.cobalt.databinding.api.createPropertyFrom
import org.hexworks.cobalt.databinding.api.expression.concat
import org.hexworks.cobalt.databinding.api.property.Property
import org.hexworks.zircon.api.Components
import org.hexworks.zircon.api.component.Component

data class ZirconCounter(private val zirconCountProperty: Property<Int> = createPropertyFrom(0)) : DisplayableAttribute {

var zirconCount: Int by zirconCountProperty.asDelegate()

override fun toComponent(width: Int): Component {
val zirconProp = createPropertyFrom("Zircons: ")
.concat(zirconCountProperty) { it.value.toString() }
return Components.header()
.withText(zirconProp.value)
.withSize(width, 1)
.build().apply {
textProperty.updateFrom(zirconProp)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package org.hexworks.cavesofzircon.attributes.types
import org.hexworks.amethyst.api.base.BaseEntityType

object Player : BaseEntityType(
name = "player"), Combatant, ItemHolder, EnergyUser, EquipmentHolder, ExperienceGainer
name = "player"), Combatant, ItemHolder, EnergyUser, EquipmentHolder, ExperienceGainer, ZirconHolder

object Wall : BaseEntityType(
name = "wall")
Expand All @@ -27,6 +27,9 @@ object StairsDown : BaseEntityType(
object StairsUp : BaseEntityType(
name = "stairs up")

object Exit : BaseEntityType(
name = "exit")

object Zircon : BaseEntityType(
name = "Zircon",
description = "A small piece of Zircon. Its value is unfathomable."), Item
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.hexworks.cavesofzircon.attributes.types

import org.hexworks.amethyst.api.entity.EntityType
import org.hexworks.cavesofzircon.attributes.ZirconCounter
import org.hexworks.cavesofzircon.extensions.GameEntity

interface ZirconHolder : EntityType

val GameEntity<ZirconHolder>.zirconCounter: ZirconCounter
get() = findAttribute(ZirconCounter::class).get()
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ import org.hexworks.cavesofzircon.attributes.ItemCombatStats
import org.hexworks.cavesofzircon.attributes.ItemIcon
import org.hexworks.cavesofzircon.attributes.NutritionalValue
import org.hexworks.cavesofzircon.attributes.Vision
import org.hexworks.cavesofzircon.attributes.ZirconCounter
import org.hexworks.cavesofzircon.attributes.flags.BlockOccupier
import org.hexworks.cavesofzircon.attributes.flags.VisionBlocker
import org.hexworks.cavesofzircon.attributes.types.Armor
import org.hexworks.cavesofzircon.attributes.types.Bat
import org.hexworks.cavesofzircon.attributes.types.BatMeat
import org.hexworks.cavesofzircon.attributes.types.Club
import org.hexworks.cavesofzircon.attributes.types.Dagger
import org.hexworks.cavesofzircon.attributes.types.Exit
import org.hexworks.cavesofzircon.attributes.types.Fungus
import org.hexworks.cavesofzircon.attributes.types.HeavyArmor
import org.hexworks.cavesofzircon.attributes.types.Jacket
Expand Down Expand Up @@ -59,6 +61,7 @@ import org.hexworks.cavesofzircon.systems.Movable
import org.hexworks.cavesofzircon.systems.StairClimber
import org.hexworks.cavesofzircon.systems.StairDescender
import org.hexworks.cavesofzircon.systems.Wanderer
import org.hexworks.cavesofzircon.systems.ZirconGatherer
import org.hexworks.cavesofzircon.world.Game
import org.hexworks.cavesofzircon.world.GameContext
import org.hexworks.zircon.api.GraphicalTilesetResources
Expand Down Expand Up @@ -91,6 +94,11 @@ object EntityFactory {
EntityPosition())
}

fun newExit() = newGameEntityOfType(Exit) {
attributes(EntityTile(GameTileRepository.EXIT),
EntityPosition())
}

fun newPlayer() = newGameEntityOfType(Player) {
attributes(
Experience(),
Expand All @@ -107,10 +115,11 @@ object EntityFactory {
EnergyLevel(1000, 1000),
Equipment(
initialWeapon = newClub(),
initialArmor = newJacket()))
initialArmor = newJacket()),
ZirconCounter())
behaviors(InputReceiver, EnergyExpender)
facets(Movable, CameraMover, StairClimber, StairDescender, Attackable, ExperienceAccumulator, Destructible,
ItemPicker, InventoryInspector, ItemDropper, EnergyExpender, DigestiveSystem)
ZirconGatherer, ItemPicker, InventoryInspector, ItemDropper, EnergyExpender, DigestiveSystem)
}

fun newFungus(fungusSpread: FungusSpread = FungusSpread()) = newGameEntityOfType(Fungus) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ object GameTileRepository {
.withBackgroundColor(GameColors.FLOOR_BACKGROUND)
.buildCharacterTile()

val EXIT = Tiles.newBuilder()
.withCharacter('+')
.withForegroundColor(GameColors.ACCENT_COLOR)
.withBackgroundColor(GameColors.FLOOR_BACKGROUND)
.buildCharacterTile()

val PLAYER = Tiles.newBuilder()
.withCharacter('@')
.withBackgroundColor(GameColors.FLOOR_BACKGROUND)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.hexworks.cavesofzircon.events

import org.hexworks.cobalt.events.api.Event

data class PlayerDied(val cause: String) : Event
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.hexworks.cavesofzircon.events

import org.hexworks.cobalt.events.api.Event

data class PlayerWonTheGame(val zircons: Int) : Event
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,21 @@ import org.hexworks.amethyst.api.base.BaseFacet
import org.hexworks.amethyst.api.entity.EntityType
import org.hexworks.cavesofzircon.commands.Destroy
import org.hexworks.cavesofzircon.commands.EntityDestroyed
import org.hexworks.cavesofzircon.events.PlayerDied
import org.hexworks.cavesofzircon.extensions.GameCommand
import org.hexworks.cavesofzircon.extensions.isPlayer
import org.hexworks.cavesofzircon.functions.logGameEvent
import org.hexworks.cavesofzircon.world.GameContext
import org.hexworks.zircon.internal.Zircon

object Destructible : BaseFacet<GameContext>() {

override fun executeCommand(command: GameCommand<out EntityType>) = command.responseWhenCommandIs(Destroy::class) { (context, destroyer, target, cause) ->
context.world.removeEntity(target)
destroyer.executeCommand(EntityDestroyed(context, target, destroyer))
if (target.isPlayer) {
Zircon.eventBus.publish(PlayerDied("You died $cause"))
}
logGameEvent("$target dies $cause.")
Consumed
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,4 @@ object ItemPicker : BaseFacet<GameContext>() {
Consumed
}

private fun World.findTopItem(position: Position3D) =
fetchBlockAt(position).flatMap { block ->
Maybe.ofNullable(block.entities.filterType<Item>().firstOrNull())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,45 @@ package org.hexworks.cavesofzircon.systems
import org.hexworks.amethyst.api.Consumed
import org.hexworks.amethyst.api.base.BaseFacet
import org.hexworks.amethyst.api.entity.EntityType
import org.hexworks.cavesofzircon.attributes.types.Exit
import org.hexworks.cavesofzircon.attributes.types.Player
import org.hexworks.cavesofzircon.attributes.types.StairsDown
import org.hexworks.cavesofzircon.attributes.types.zirconCounter
import org.hexworks.cavesofzircon.blocks.GameBlock
import org.hexworks.cavesofzircon.commands.MoveDown
import org.hexworks.cavesofzircon.events.PlayerWonTheGame
import org.hexworks.cavesofzircon.extensions.GameCommand
import org.hexworks.cavesofzircon.extensions.position
import org.hexworks.cavesofzircon.extensions.whenTypeIs
import org.hexworks.cavesofzircon.functions.logGameEvent
import org.hexworks.cavesofzircon.world.GameContext
import org.hexworks.cobalt.datatypes.extensions.map
import org.hexworks.zircon.internal.Zircon

object StairDescender : BaseFacet<GameContext>() {

override fun executeCommand(command: GameCommand<out EntityType>) = command.responseWhenCommandIs(MoveDown::class) { (context, player) ->
override fun executeCommand(command: GameCommand<out EntityType>) = command.responseWhenCommandIs(MoveDown::class) { (context, source) ->
val world = context.world
val playerPos = player.position
world.fetchBlockAt(playerPos).map { block ->
if (block.hasStairsDown) {
logGameEvent("You move down one level...")
world.moveEntity(player, playerPos.withRelativeZ(-1))
world.scrollOneDown()
} else {
logGameEvent("You search for a trapdoor, but you find nothing.")
val pos = source.position
world.fetchBlockAt(pos).map { block ->
when {
block.hasStairsDown -> {
logGameEvent("You move down one level...")
world.moveEntity(source, pos.withRelativeZ(-1))
world.scrollOneDown()
}
block.hasExit -> source.whenTypeIs<Player> {
Zircon.eventBus.publish(PlayerWonTheGame(it.zirconCounter.zirconCount))
}
else -> logGameEvent("You search for a trapdoor, but you find nothing.")
}
}
Consumed
}

private val GameBlock.hasStairsDown: Boolean
get() = this.entities.any { it.type == StairsDown }

private val GameBlock.hasExit: Boolean
get() = this.entities.any { it.type == Exit }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.hexworks.cavesofzircon.systems

import org.hexworks.amethyst.api.Command
import org.hexworks.amethyst.api.Consumed
import org.hexworks.amethyst.api.Pass
import org.hexworks.amethyst.api.Response
import org.hexworks.amethyst.api.base.BaseFacet
import org.hexworks.amethyst.api.entity.EntityType
import org.hexworks.cavesofzircon.attributes.ZirconCounter
import org.hexworks.cavesofzircon.attributes.types.Zircon
import org.hexworks.cavesofzircon.attributes.types.ZirconHolder
import org.hexworks.cavesofzircon.attributes.types.zirconCounter
import org.hexworks.cavesofzircon.commands.PickItemUp
import org.hexworks.cavesofzircon.extensions.whenTypeIs
import org.hexworks.cavesofzircon.functions.logGameEvent
import org.hexworks.cavesofzircon.world.GameContext
import org.hexworks.cobalt.datatypes.extensions.map

object ZirconGatherer : BaseFacet<GameContext>(ZirconCounter::class) {

override fun executeCommand(command: Command<out EntityType, GameContext>) = command.responseWhenCommandIs(PickItemUp::class) {
val (context, source, position) = it
var response: Response = Pass
val world = context.world
world.findTopItem(position).map { item ->
source.whenTypeIs<ZirconHolder> { zirconHolder ->
if (item.type == Zircon) {
zirconHolder.zirconCounter.zirconCount++
world.removeEntity(item)
logGameEvent("$zirconHolder picked up a Zircon!")
response = Consumed
}
}
}
response
}
}
20 changes: 13 additions & 7 deletions src/main/kotlin/org/hexworks/cavesofzircon/view/LoseView.kt
Original file line number Diff line number Diff line change
@@ -1,43 +1,49 @@
package org.hexworks.cavesofzircon.view

import org.hexworks.zircon.api.ColorThemes
import org.hexworks.cavesofzircon.GameConfig
import org.hexworks.cavesofzircon.GameConfig.WORLD_SIZE
import org.hexworks.cavesofzircon.world.GameBuilder
import org.hexworks.zircon.api.Components
import org.hexworks.zircon.api.component.ComponentAlignment
import org.hexworks.zircon.api.component.ComponentAlignment.BOTTOM_LEFT
import org.hexworks.zircon.api.component.ComponentAlignment.BOTTOM_RIGHT
import org.hexworks.zircon.api.extensions.onComponentEvent
import org.hexworks.zircon.api.graphics.BoxType
import org.hexworks.zircon.api.mvc.base.BaseView
import org.hexworks.zircon.api.uievent.ComponentEventType
import org.hexworks.zircon.api.uievent.Processed

class LoseView : BaseView() {
class LoseView(private val causeOfDeath: String) : BaseView() {

override val theme = ColorThemes.arc()
override val theme = GameConfig.THEME

override fun onDock() {
val msg = "Game Over"
val header = Components.textBox()
.withContentWidth(30)
.addHeader(msg)
.addParagraph(causeOfDeath)
.addNewLine()
.withAlignmentWithin(screen, ComponentAlignment.CENTER)
.build()
val restartButton = Components.button()
.withAlignmentAround(header, ComponentAlignment.BOTTOM_LEFT)
.withAlignmentAround(header, BOTTOM_LEFT)
.withText("Restart")
.wrapSides(false)
.wrapWithBox()
.withBoxType(BoxType.SINGLE)
.build()
val exitButton = Components.button()
.withAlignmentAround(header, ComponentAlignment.BOTTOM_RIGHT)
.withAlignmentAround(header, BOTTOM_RIGHT)
.withText("Quit")
.wrapSides(false)
.wrapWithBox()
.withBoxType(BoxType.SINGLE)
.build()

// TODO: tutorial
restartButton.onComponentEvent(ComponentEventType.ACTIVATED) {
replaceWith(PlayView())
replaceWith(PlayView(GameBuilder(
worldSize = WORLD_SIZE).buildGame()))
close()
Processed
}
Expand Down
11 changes: 10 additions & 1 deletion src/main/kotlin/org/hexworks/cavesofzircon/view/PlayView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ package org.hexworks.cavesofzircon.view
import org.hexworks.cavesofzircon.GameConfig
import org.hexworks.cavesofzircon.blocks.GameBlock
import org.hexworks.cavesofzircon.events.GameLogEvent
import org.hexworks.cavesofzircon.events.PlayerDied
import org.hexworks.cavesofzircon.events.PlayerGainedLevel
import org.hexworks.cavesofzircon.events.PlayerWonTheGame
import org.hexworks.cavesofzircon.view.dialog.LevelUpDialog
import org.hexworks.cavesofzircon.view.fragment.PlayerStatsFragment
import org.hexworks.cavesofzircon.world.Game
Expand Down Expand Up @@ -60,7 +62,14 @@ class PlayView(private val game: Game = GameBuilder.defaultGame()) : BaseView()
Zircon.eventBus.subscribe<PlayerGainedLevel> {
screen.openModal(LevelUpDialog(screen, game.player))
}

Zircon.eventBus.subscribe<PlayerWonTheGame> {
replaceWith(WinView(it.zircons))
close()
}
Zircon.eventBus.subscribe<PlayerDied> {
replaceWith(LoseView(it.cause))
close()
}
val gameComponent = GameComponents.newGameComponentBuilder<Tile, GameBlock>()
.withGameArea(game.world)
.withVisibleSize(game.world.visibleSize())
Expand Down
17 changes: 10 additions & 7 deletions src/main/kotlin/org/hexworks/cavesofzircon/view/WinView.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.hexworks.cavesofzircon.view

import org.hexworks.zircon.api.ColorThemes
import org.hexworks.cavesofzircon.GameConfig
import org.hexworks.cavesofzircon.world.GameBuilder
import org.hexworks.zircon.api.Components
import org.hexworks.zircon.api.component.ComponentAlignment
import org.hexworks.zircon.api.extensions.onComponentEvent
Expand All @@ -9,15 +10,18 @@ import org.hexworks.zircon.api.mvc.base.BaseView
import org.hexworks.zircon.api.uievent.ComponentEventType
import org.hexworks.zircon.api.uievent.Processed

class WinView : BaseView() {
class WinView(private val zircons: Int) : BaseView() {

override val theme = ColorThemes.arc()
override val theme = GameConfig.THEME

override fun onDock() {
val msg = "You won!"
val header = Components.textBox()
.withContentWidth(30)
.withContentWidth(GameConfig.WINDOW_WIDTH / 2)
.addHeader(msg)
.addNewLine()
.addParagraph("Congratulations! You have escaped from Caves of Zircon!", withNewLine = false)
.addParagraph("You've managed to find $zircons Zircons.")
.withAlignmentWithin(screen, ComponentAlignment.CENTER)
.build()
val restartButton = Components.button()
Expand All @@ -35,9 +39,9 @@ class WinView : BaseView() {
.withBoxType(BoxType.SINGLE)
.build()

// TODO: tutorial
restartButton.onComponentEvent(ComponentEventType.ACTIVATED) {
replaceWith(PlayView())
replaceWith(PlayView(GameBuilder(
worldSize = GameConfig.WORLD_SIZE).buildGame()))
close()
Processed
}
Expand All @@ -52,4 +56,3 @@ class WinView : BaseView() {
screen.addComponent(exitButton)
}
}

Loading

0 comments on commit b105517

Please sign in to comment.