diff --git a/README.md b/README.md index 09dfad0..0a9d966 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ dependencies { } ``` -## A simple game +## Getting started with a simple game To create a simple `Game` you need: an `InOut` object for input and output, a `Character` object for your main character, and a `Scene` for your initial scene. @@ -118,8 +118,8 @@ val scene = Scene("hello-keep", "Hello Keep", "Keep is a text game engine.", The **Keep Engine** can do much more things to help you design your text-based game, such as: -- [Characters with state](doc/characters.md) - [Items with state](doc/items.md) +- [Characters with state](doc/characters.md) - [Dialogue Trees](doc/dialogues.md) - [Custom Actions](doc/actions.md) - [Actions and Events](doc/events.md) diff --git a/doc/characters.md b/doc/characters.md index 82f5c2d..fa8aa6a 100644 --- a/doc/characters.md +++ b/doc/characters.md @@ -1,3 +1,5 @@ # Keep Engine ## Characters + +## diff --git a/doc/items.md b/doc/items.md index 033e223..96f5645 100644 --- a/doc/items.md +++ b/doc/items.md @@ -1,3 +1,51 @@ -# Keep Engine +# Keep Engine - Items -## Items +## Simple items + +The most simple items are declared using the `item` function with a `key` to identify it, a display `name`, and a `description`. Typically, a callback is registered using `onUse`, it will be called when the `Use` action is used on the item. + +The following example shows a potion that can be used by the player. + +```kotlin +val potion = + item( + "potion", + "Potion", + "A potion with magical powers.", + canBeTaken = true + ) onUse { + io.paragraph("You feel magical and refreshed.") + } +``` + +## Stateful items + +Items can hold state, allowing the world to react and be modified by the player's actions. Use an overload of the `item` function, and declare `key`, `initialState` and `states` parameters. + +Each state has its own `key`, also the state have `name` and `description` properties that replace the item ones. Each state can have its own subscriptions to `onUse` and other actions, allowing the item to change its behavior. + +The following example shows a switch that can be turned on or off by the player. + +```kotlin +val switch = + item( + "switch", + "off", + itemState( + "off", + "switch (off)", + "An example of an item with state in Keep. The switch is off." + ) onUse { + target.change("on") + io.paragraph("Turn the switch on...") + }, + itemState( + "on", + "switch (on)", + "An example of an item with state in Keep. The switch is on." + ) onUse { + target.change("off") + io.paragraph("Turn the switch off...") + } + ) +``` diff --git a/samples/src/main/kotlin/tech/alephia/keep/samples/advanced/characters/alice.kt b/samples/src/main/kotlin/tech/alephia/keep/samples/advanced/characters/alice.kt new file mode 100644 index 0000000..6a016cc --- /dev/null +++ b/samples/src/main/kotlin/tech/alephia/keep/samples/advanced/characters/alice.kt @@ -0,0 +1,14 @@ +package tech.alephia.keep.samples.advanced.characters + +import tech.alephia.keep.core.entities.characters.npc +import tech.alephia.keep.core.events.onTalk + +val alice = + npc( + "alice", + "Alice", + "Alice, another NPC." + ) onTalk { + io.paragraph("${target.name}: Hi, how have you been?") + io.promptContinue() + } diff --git a/samples/src/main/kotlin/tech/alephia/keep/samples/advanced/characters/bob.kt b/samples/src/main/kotlin/tech/alephia/keep/samples/advanced/characters/bob.kt new file mode 100644 index 0000000..8fb14b7 --- /dev/null +++ b/samples/src/main/kotlin/tech/alephia/keep/samples/advanced/characters/bob.kt @@ -0,0 +1,14 @@ +package tech.alephia.keep.samples.advanced.characters + +import tech.alephia.keep.core.entities.characters.npc +import tech.alephia.keep.core.events.onTalk + +val bob = + npc( + "bob", + "Bob", + "Bob, an NPC." + ) onTalk { + io.paragraph("${target.name}: Hello ${game.mainCharacter.name}!.") + io.promptContinue() + } diff --git a/samples/src/main/kotlin/tech/alephia/keep/samples/advanced/characters/john.kt b/samples/src/main/kotlin/tech/alephia/keep/samples/advanced/characters/john.kt new file mode 100644 index 0000000..8252708 --- /dev/null +++ b/samples/src/main/kotlin/tech/alephia/keep/samples/advanced/characters/john.kt @@ -0,0 +1,5 @@ +package tech.alephia.keep.samples.advanced.characters + +import tech.alephia.keep.core.entities.characters.mainCharacter + +val john = mainCharacter("player", "John") diff --git a/samples/src/main/kotlin/tech/alephia/keep/samples/advanced/items/potion.kt b/samples/src/main/kotlin/tech/alephia/keep/samples/advanced/items/potion.kt new file mode 100644 index 0000000..c61e029 --- /dev/null +++ b/samples/src/main/kotlin/tech/alephia/keep/samples/advanced/items/potion.kt @@ -0,0 +1,14 @@ +package tech.alephia.keep.samples.advanced.items + +import tech.alephia.keep.core.entities.items.item +import tech.alephia.keep.core.events.onUse + +val potion = + item( + "potion", + "Potion", + "A potion with magical powers.", + canBeTaken = true + ) onUse { + io.paragraph("You feel magical and refreshed.") + } diff --git a/samples/src/main/kotlin/tech/alephia/keep/samples/advanced/items/switch.kt b/samples/src/main/kotlin/tech/alephia/keep/samples/advanced/items/switch.kt new file mode 100644 index 0000000..22291d1 --- /dev/null +++ b/samples/src/main/kotlin/tech/alephia/keep/samples/advanced/items/switch.kt @@ -0,0 +1,27 @@ +package tech.alephia.keep.samples.advanced.items + +import tech.alephia.keep.core.entities.items.item +import tech.alephia.keep.core.entities.items.itemState +import tech.alephia.keep.core.events.onUse + +val switch = + item( + "switch", + "off", + itemState( + "off", + "switch (off)", + "An example of an item with state in Keep. The switch is off." + ) onUse { + target.change("on") + io.paragraph("Turn the switch on...") + }, + itemState( + "on", + "switch (on)", + "An example of an item with state in Keep. The switch is on." + ) onUse { + target.change("off") + io.paragraph("Turn the switch off...") + } + ) diff --git a/samples/src/main/kotlin/tech/alephia/keep/samples/advanced/main.kt b/samples/src/main/kotlin/tech/alephia/keep/samples/advanced/main.kt new file mode 100644 index 0000000..6a9a6e7 --- /dev/null +++ b/samples/src/main/kotlin/tech/alephia/keep/samples/advanced/main.kt @@ -0,0 +1,20 @@ +package tech.alephia.keep.samples.advanced + +import tech.alephia.keep.core.Game +import tech.alephia.keep.delivery.InOut +import tech.alephia.keep.samples.advanced.characters.john +import tech.alephia.keep.samples.advanced.scenes.keepLobby +import tech.alephia.keep.samples.advanced.scenes.room + +fun main() { + val inOut = InOut() + + val scenes = listOf(keepLobby, room) + val game = Game(inOut, john, scenes, "keep-lobby") + + game.start() + + while (true) { + game.draw() + } +} diff --git a/samples/src/main/kotlin/tech/alephia/keep/samples/advanced/scenes/keepLobby.kt b/samples/src/main/kotlin/tech/alephia/keep/samples/advanced/scenes/keepLobby.kt new file mode 100644 index 0000000..7d5867b --- /dev/null +++ b/samples/src/main/kotlin/tech/alephia/keep/samples/advanced/scenes/keepLobby.kt @@ -0,0 +1,20 @@ +package tech.alephia.keep.samples.advanced.scenes + +import tech.alephia.keep.core.actions.* +import tech.alephia.keep.core.scenes.Scene +import tech.alephia.keep.core.scenes.actions +import tech.alephia.keep.core.scenes.characters +import tech.alephia.keep.core.scenes.items +import tech.alephia.keep.samples.advanced.characters.alice +import tech.alephia.keep.samples.advanced.characters.bob +import tech.alephia.keep.samples.advanced.items.potion +import tech.alephia.keep.samples.advanced.items.switch + +val commonActions = actions(Take(), Leave(), Look(), Use(), Talk()) + +val keepLobby = Scene( + "keep-lobby", "Keep", "Keep is a text game engine.", + commonActions + Goto("room", "Go to the next room"), + items(potion, switch), + characters(alice, bob) +) diff --git a/samples/src/main/kotlin/tech/alephia/keep/samples/advanced/scenes/room.kt b/samples/src/main/kotlin/tech/alephia/keep/samples/advanced/scenes/room.kt new file mode 100644 index 0000000..6c77c3d --- /dev/null +++ b/samples/src/main/kotlin/tech/alephia/keep/samples/advanced/scenes/room.kt @@ -0,0 +1,10 @@ +package tech.alephia.keep.samples.advanced.scenes + +import tech.alephia.keep.core.actions.Goto +import tech.alephia.keep.core.scenes.Scene +import tech.alephia.keep.core.scenes.actions + +val room = Scene( + "room", "Room", "An empty room.", + actions(Goto("keep.lobby", "Go back")) +) diff --git a/samples/src/main/kotlin/tech/alephia/keep/samples/addingitems/main.kt b/samples/src/main/kotlin/tech/alephia/keep/samples/basic/addingitems/main.kt similarity index 94% rename from samples/src/main/kotlin/tech/alephia/keep/samples/addingitems/main.kt rename to samples/src/main/kotlin/tech/alephia/keep/samples/basic/addingitems/main.kt index 5a30b26..7ba11d2 100644 --- a/samples/src/main/kotlin/tech/alephia/keep/samples/addingitems/main.kt +++ b/samples/src/main/kotlin/tech/alephia/keep/samples/basic/addingitems/main.kt @@ -1,4 +1,4 @@ -package tech.alephia.keep.samples.addingitems +package tech.alephia.keep.samples.basic.addingitems import tech.alephia.keep.core.Game import tech.alephia.keep.core.actions.Leave diff --git a/samples/src/main/kotlin/tech/alephia/keep/samples/addingnpcs/main.kt b/samples/src/main/kotlin/tech/alephia/keep/samples/basic/addingnpcs/main.kt similarity index 96% rename from samples/src/main/kotlin/tech/alephia/keep/samples/addingnpcs/main.kt rename to samples/src/main/kotlin/tech/alephia/keep/samples/basic/addingnpcs/main.kt index ec269b1..ef80173 100644 --- a/samples/src/main/kotlin/tech/alephia/keep/samples/addingnpcs/main.kt +++ b/samples/src/main/kotlin/tech/alephia/keep/samples/basic/addingnpcs/main.kt @@ -1,4 +1,4 @@ -package tech.alephia.keep.samples.addingnpcs +package tech.alephia.keep.samples.basic.addingnpcs import tech.alephia.keep.core.Game import tech.alephia.keep.core.actions.Talk diff --git a/samples/src/main/kotlin/tech/alephia/keep/samples/changingscenes/main.kt b/samples/src/main/kotlin/tech/alephia/keep/samples/basic/changingscenes/main.kt similarity index 93% rename from samples/src/main/kotlin/tech/alephia/keep/samples/changingscenes/main.kt rename to samples/src/main/kotlin/tech/alephia/keep/samples/basic/changingscenes/main.kt index 7e83eff..38b2b33 100644 --- a/samples/src/main/kotlin/tech/alephia/keep/samples/changingscenes/main.kt +++ b/samples/src/main/kotlin/tech/alephia/keep/samples/basic/changingscenes/main.kt @@ -1,4 +1,4 @@ -package tech.alephia.keep.samples.changingscenes +package tech.alephia.keep.samples.basic.changingscenes import tech.alephia.keep.core.Game import tech.alephia.keep.core.actions.Goto diff --git a/samples/src/main/kotlin/tech/alephia/keep/samples/hellokeep/main.kt b/samples/src/main/kotlin/tech/alephia/keep/samples/basic/hellokeep/main.kt similarity index 100% rename from samples/src/main/kotlin/tech/alephia/keep/samples/hellokeep/main.kt rename to samples/src/main/kotlin/tech/alephia/keep/samples/basic/hellokeep/main.kt diff --git a/src/main/kotlin/tech/alephia/keep/core/entities/items/dsl.kt b/src/main/kotlin/tech/alephia/keep/core/entities/items/dsl.kt index e9360fd..6427108 100644 --- a/src/main/kotlin/tech/alephia/keep/core/entities/items/dsl.kt +++ b/src/main/kotlin/tech/alephia/keep/core/entities/items/dsl.kt @@ -8,9 +8,9 @@ fun item( description: String, indefiniteArticle: IndefiniteArticle = IndefiniteArticle.A, canBeTaken: Boolean = false -) = SomeItem(key, name, description, indefiniteArticle, canBeTaken, Subscriptions(defaultItemSubscriptions())) +): Item = SomeItem(key, name, description, indefiniteArticle, canBeTaken, Subscriptions(defaultItemSubscriptions())) -fun item(key: String, initialState: String, vararg states: ItemState) = +fun item(key: String, initialState: String, vararg states: ItemState): Item = StatefulItem(key, initialState, states.toList()) fun itemState(