Skip to content

Commit

Permalink
Merge pull request #56 from mmacy/cli-menu-stubs
Browse files Browse the repository at this point in the history
character creator CLI with questionary
  • Loading branch information
mmacy committed May 21, 2024
2 parents f7d17ff + cac06f8 commit 28ff573
Show file tree
Hide file tree
Showing 12 changed files with 421 additions and 252 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# OSR Console: Adventures in turn-based text

OSR Console is a turn-based dungeon crawler RPG in the Old-School Renaissance (OSR) style for your terminal. The game's main library, `osrlib`, is written in Python, as is its user interface which uses the [Textual](https://textual.textualize.io/) TUI framework.
OSR Console is an SDK for a turn-based dungeon crawler RPG in the Old-School Renaissance (OSR) style for your terminal. The SDK's main library, `osrlib`, is written in Python, as is the example user interface which uses the [Textual](https://textual.textualize.io/) TUI framework.

![Screenshot of the OSR Console application running in an iTerm2 window in macOS](images/character-sheet-01.png)

Expand All @@ -12,7 +12,7 @@ OSR Console is a turn-based dungeon crawler RPG in the Old-School Renaissance (O

## Installation

This is a monorepo that houses three projects: the game's library, `osrlib`, that library's `tests`, and an example user interface, `osrgame`.
This monorepo houses three projects: the game's library, `osrlib`, that library's `tests`, and an example user interface, `osrgame`.

For more information about each, see their respective `README.md` files:

Expand Down Expand Up @@ -49,4 +49,4 @@ This screenshot shows an example of LLM-generated content in the (very much *for
## Credits

- Project owner: [@mmacy](https://github.com/mmacy)
- Game rules and mechanics heavily inspired by the TSR's 1981 versions of the Dungeons & Dragons Basic and Expert sets, or *D&D B/X*.
- Game rules and mechanics heavily inspired by TSR's 1981 versions of the Dungeons & Dragons Basic and Expert sets, or *D&D B/X*.
168 changes: 166 additions & 2 deletions osrcli/src/osrcli/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,167 @@
import json
import os

import questionary
from questionary import Separator

from osrlib.player_character import PlayerCharacter
from osrlib.enums import CharacterClassType
from osrlib.party import Party


def clear_screen():
os.system("cls" if os.name == "nt" else "clear")


back = "⬅ Back"
exit_app = "❌ Exit"
nav_instruction = "📜"
nav_instruction_arrow_keys = "(use arrow keys)"
separator_top = "==--=="
separator_bottom = "------"

icon_arrow_left = "⬅️"
icon_arrow_right = "➡️"
icon_arrow_back = "🔙"
icon_tri_left = "◀️"
icon_select = "▶️"
icon_bubble = "💬"
icon_cloud = "☁️"
icon_crown = "👑"
icon_dash = "➖"
icon_diamon_blue = "🔹"
icon_diamond_orange = "🔸"
icon_die = "🎲"
icon_earth = "🌍"
icon_finger = "👉"
icon_fire = "🔥"
icon_flag = "🚩"
icon_gear = "⚙️"
icon_gem = "💎"
icon_heart = "❤️"
icon_key = "🔑"
icon_lightning = "⚡"
icon_lock = "🔒"
icon_map = "🗺️"
icon_moon = "🌙"
icon_questionmark = "❓"
icon_rain = "🌧️"
icon_scroll = "📜"
icon_arrowhead_right_sm = "➤"
icon_shield = "🛡️"
icon_skull = "💀"
icon_snowflake = "❄️"
icon_star = "⭐"
icon_star = "⭐"
icon_sun = "☀️"
icon_sword = "⚔️"
icon_treasure = "💰"
icon_water = "💧"
icon_wind = "💨"
icon_floppy_disk = "💾"
icon_x = "❌"
icon_prohibited = "🚫"


class MainMenu:
def show(self):
while True:
choice = questionary.select(
"Welcome to OSR CLI",
qmark=icon_scroll,
pointer=icon_select,
instruction=icon_scroll,
choices=[
Separator(separator_top),
"Create character",
"Create party",
"Create adventure",
"Play adventure",
"Settings",
Separator(separator_bottom),
exit_app,
],
).ask()
if choice == "Create character":
character_menu = CreateCharacterMenu()
character_menu.show()
elif choice == exit_app:
break


class CreateCharacterMenu:
def show(self):
while True:
character_name = questionary.text("Character name:").ask()

class_choice = questionary.select(
"Character class:",
pointer=icon_select,
instruction=nav_instruction_arrow_keys,
choices=[
Separator(separator_top),
*[c.value for c in CharacterClassType],
Separator(separator_bottom),
back,
],
).ask()

if class_choice != back:
character_class = CharacterClassType(class_choice)
character = PlayerCharacter(character_name, character_class)
questionary.print(str(character))

while True:
reroll_choice = questionary.confirm(
"Reroll abilities",
instruction="[Y/n]: ",
default=True,
).ask()

if reroll_choice:
character.roll_abilities()
questionary.print(str(character))
else:
break

save_character = questionary.confirm(
"Save character",
instruction="[Y/n]: ",
default=True,
).ask()
if save_character:
save_file = questionary.text(
"File name:",
default=character.name.lower().replace(' ', '_').strip() + ".json",
).ask()
save_dir = questionary.path("Directory:").ask()

# Expand the tilde to the user's home directory path if present
save_dir = os.path.expanduser(save_dir)

# Check if the directory exists and create it if necessary
full_path = os.path.join(save_dir, save_file)
os.makedirs(os.path.dirname(full_path), exist_ok=True)

with open(full_path, "w") as f:
f.write(json.dumps(character.to_dict(), indent=4))

questionary.print(
f"{icon_floppy_disk} Character saved to " + full_path
)

if questionary.confirm(
"Create another character", instruction="[Y/n]: "
).ask():
continue
else:
break
else:
break


def main() -> int:
print("Hello from osrcli!")
return 0
main_menu = MainMenu()
clear_screen()
main_menu.show()
return 0
Loading

0 comments on commit 28ff573

Please sign in to comment.