Skip to content

Commit e906f03

Browse files
author
adam-arold
committed
Add the first monster in the game
1 parent 9986a6f commit e906f03

11 files changed

Lines changed: 130 additions & 13 deletions

File tree

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,13 @@
22

33
This project is part of the [How to Make a Roguelike](https://hexworks.org/posts/tutorials/2018/11/04/how-to-make-a-roguelike.html)
44
tutorial. Check out the article series if you want to make the most ouf of this project.
5+
6+
7+
## Improvements
8+
9+
These are the future improvements we'll add to the tutorial based on feedback:
10+
11+
- [x] Explain `also` (and other scoping functions) in #4 (where it is first used) instead of #6
12+
- [ ] Explain the point of `tryToFindAttribute` instead of using `findAttribute`: we don't need
13+
the flexibility and we're using mandatory attributes
14+

src/main/kotlin/org/hexworks/cavesofzircon/GameConfig.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ object GameConfig {
2222

2323
val WORLD_SIZE = Sizes.create3DSize(WINDOW_WIDTH * 2, WINDOW_HEIGHT * 2 , DUNGEON_LEVELS)
2424

25+
// entities
26+
const val FUNGI_PER_LEVEL = 15
27+
const val MAXIMUM_FUNGUS_SPREAD = 20
28+
2529
fun buildAppConfig() = AppConfigs.newConfig()
2630
.enableBetaFeatures()
2731
.withDefaultTileset(TILESET)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package org.hexworks.cavesofzircon.attributes
2+
3+
import org.hexworks.amethyst.api.Attribute
4+
import org.hexworks.cavesofzircon.GameConfig
5+
6+
data class FungusSpread(
7+
var spreadCount: Int = 0,
8+
val maximumSpread: Int = GameConfig.MAXIMUM_FUNGUS_SPREAD) : Attribute

src/main/kotlin/org/hexworks/cavesofzircon/attributes/types/EntityTypes.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,6 @@ object Player : BaseEntityType(
77

88
object Wall : BaseEntityType(
99
name = "wall")
10+
11+
object Fungus : BaseEntityType(
12+
name = "fungus")

src/main/kotlin/org/hexworks/cavesofzircon/builders/EntityFactory.kt

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,18 @@ package org.hexworks.cavesofzircon.builders
33
import org.hexworks.amethyst.api.Entities
44
import org.hexworks.amethyst.api.builder.EntityBuilder
55
import org.hexworks.amethyst.api.entity.EntityType
6+
import org.hexworks.cavesofzircon.attributes.EntityActions
67
import org.hexworks.cavesofzircon.attributes.EntityPosition
78
import org.hexworks.cavesofzircon.attributes.EntityTile
8-
import org.hexworks.cavesofzircon.attributes.types.Player
9-
import org.hexworks.cavesofzircon.systems.CameraMover
10-
import org.hexworks.cavesofzircon.systems.InputReceiver
11-
import org.hexworks.cavesofzircon.systems.Movable
12-
import org.hexworks.cavesofzircon.world.GameContext
9+
import org.hexworks.cavesofzircon.attributes.FungusSpread
1310
import org.hexworks.cavesofzircon.attributes.flags.BlockOccupier
11+
import org.hexworks.cavesofzircon.attributes.types.Fungus
12+
import org.hexworks.cavesofzircon.attributes.types.Player
1413
import org.hexworks.cavesofzircon.attributes.types.Wall
15-
import org.hexworks.cavesofzircon.attributes.EntityActions
14+
import org.hexworks.cavesofzircon.commands.Attack
1615
import org.hexworks.cavesofzircon.commands.Dig
17-
import org.hexworks.cavesofzircon.systems.Diggable
16+
import org.hexworks.cavesofzircon.systems.*
17+
import org.hexworks.cavesofzircon.world.GameContext
1818

1919
fun <T : EntityType> newGameEntityOfType(type: T, init: EntityBuilder<T, GameContext>.() -> Unit) =
2020
Entities.newEntityOfType(type, init)
@@ -25,7 +25,7 @@ object EntityFactory {
2525
attributes(
2626
EntityPosition(),
2727
EntityTile(GameTileRepository.PLAYER),
28-
EntityActions(Dig::class))
28+
EntityActions(Dig::class, Attack::class))
2929
behaviors(InputReceiver)
3030
facets(Movable, CameraMover)
3131
}
@@ -37,5 +37,14 @@ object EntityFactory {
3737
EntityTile(GameTileRepository.WALL))
3838
facets(Diggable)
3939
}
40+
41+
fun newFungus(fungusSpread: FungusSpread = FungusSpread()) = newGameEntityOfType(Fungus) {
42+
attributes(BlockOccupier,
43+
EntityPosition(),
44+
EntityTile(GameTileRepository.FUNGUS),
45+
fungusSpread)
46+
facets(Attackable)
47+
behaviors(FungusGrowth)
48+
}
4049
}
4150

src/main/kotlin/org/hexworks/cavesofzircon/builders/GameColors.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,7 @@ object GameColors {
99
val FLOOR_FOREGROUND = TileColors.fromString("#75715E")
1010
val FLOOR_BACKGROUND = TileColors.fromString("#1e2320")
1111

12+
val FUNGUS_COLOR = TileColors.fromString("#85DD1B")
13+
1214
val ACCENT_COLOR = TileColors.fromString("#FFCD22")
1315
}

src/main/kotlin/org/hexworks/cavesofzircon/builders/GameTileRepository.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,10 @@ object GameTileRepository {
2525
.withBackgroundColor(GameColors.FLOOR_BACKGROUND)
2626
.withForegroundColor(GameColors.ACCENT_COLOR)
2727
.buildCharacterTile()
28+
29+
val FUNGUS = Tiles.newBuilder()
30+
.withCharacter('f')
31+
.withBackgroundColor(GameColors.FLOOR_BACKGROUND)
32+
.withForegroundColor(GameColors.FUNGUS_COLOR)
33+
.buildCharacterTile()
2834
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package org.hexworks.cavesofzircon.commands
2+
3+
import org.hexworks.amethyst.api.entity.EntityType
4+
import org.hexworks.cavesofzircon.extensions.GameEntity
5+
import org.hexworks.cavesofzircon.world.GameContext
6+
7+
data class Attack(override val context: GameContext,
8+
override val source: GameEntity<EntityType>,
9+
override val target: GameEntity<EntityType>) : EntityAction<EntityType, EntityType>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.hexworks.cavesofzircon.systems
2+
3+
import org.hexworks.amethyst.api.Consumed
4+
import org.hexworks.amethyst.api.base.BaseFacet
5+
import org.hexworks.amethyst.api.entity.EntityType
6+
import org.hexworks.cavesofzircon.commands.Attack
7+
import org.hexworks.cavesofzircon.extensions.GameCommand
8+
import org.hexworks.cavesofzircon.world.GameContext
9+
10+
object Attackable : BaseFacet<GameContext>() {
11+
12+
override fun executeCommand(command: GameCommand<out EntityType>) = command.responseWhenCommandIs(Attack::class) { (context, attacker, target) ->
13+
context.world.removeEntity(target)
14+
Consumed
15+
}
16+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package org.hexworks.cavesofzircon.systems
2+
3+
import org.hexworks.amethyst.api.base.BaseBehavior
4+
import org.hexworks.amethyst.api.entity.EntityType
5+
import org.hexworks.cavesofzircon.attributes.FungusSpread
6+
import org.hexworks.cavesofzircon.builders.EntityFactory
7+
import org.hexworks.cavesofzircon.extensions.GameEntity
8+
import org.hexworks.cavesofzircon.extensions.position
9+
import org.hexworks.cavesofzircon.extensions.tryToFindAttribute
10+
import org.hexworks.cavesofzircon.world.GameContext
11+
import org.hexworks.cobalt.datatypes.extensions.map
12+
import org.hexworks.zircon.api.Sizes
13+
14+
object FungusGrowth : BaseBehavior<GameContext>(FungusSpread::class) {
15+
16+
override fun update(entity: GameEntity<out EntityType>, context: GameContext): Boolean {
17+
val world = context.world
18+
val fungusSpread = entity.tryToFindAttribute(FungusSpread::class)
19+
val (spreadCount, maxSpread) = fungusSpread
20+
return if (spreadCount < maxSpread && Math.random() < 0.015) {
21+
world.findEmptyLocationWithin(
22+
offset = entity.position
23+
.withRelativeX(-1)
24+
.withRelativeY(-1),
25+
size = Sizes.create3DSize(3, 3, 0)).map { emptyLocation ->
26+
world.addEntity(EntityFactory.newFungus(fungusSpread), emptyLocation)
27+
fungusSpread.spreadCount++
28+
}
29+
true
30+
} else false
31+
}
32+
}

0 commit comments

Comments
 (0)