Skip to content

Refactor modules to make them more consistent and split out CLI #31

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Dec 8, 2024
40 changes: 9 additions & 31 deletions lib/rule_systems/characters.ex → lib/characters.ex
Original file line number Diff line number Diff line change
@@ -1,44 +1,22 @@
defmodule ExTTRPGDev.RuleSystems.Characters do
defmodule ExTTRPGDev.Characters do
@moduledoc """
This module handles the definition of rule system characters, and what they do
This module handles handles character operations
"""
alias ExTTRPGDev.Characters.Character
alias ExTTRPGDev.Characters.Metadata
alias ExTTRPGDev.Globals

defmodule CharacterMetadata do
@moduledoc """
Metadata for an individual charater
"""
defstruct [:slug, :rule_system]
end

defmodule Character do
@moduledoc """
Definition of an individual character
"""
defstruct [:name, :ability_scores, :metadata]
end

def from_json!(character_json) when is_bitstring(character_json) do
character_json
|> Poison.decode!(
as: %Character{
metadata: %CharacterMetadata{
rule_system: %ExTTRPGDev.RuleSystems.Metadata{}
}
}
)
end

@doc """
Get the file path for a character

## Examples

iex> Characters.character_file_path!(%Character{metadata: %CharacterMetadata{slug: "mr_whiskers"}})
iex> Characters.character_file_path!(%Character{metadata: %Characters.Metadata{slug: "mr_whiskers"}})
"mr_whiskers.json"
"""
def character_file_path!(%Character{metadata: %CharacterMetadata{slug: slug}}),
do: character_file_path!(slug)
def character_file_path!(%Character{metadata: %Metadata{slug: slug}}) do
character_file_path!(slug)
end

def character_file_path!(character_slug) when is_bitstring(character_slug) do
Path.join(Globals.characters_path(), "#{character_slug}.json")
Expand Down Expand Up @@ -112,6 +90,6 @@ defmodule ExTTRPGDev.RuleSystems.Characters do
def load_character!(character_slug) do
character_file_path!(character_slug)
|> File.read!()
|> from_json!()
|> Character.from_json!()
end
end
51 changes: 51 additions & 0 deletions lib/characters/character.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
defmodule ExTTRPGDev.Characters.Character do
alias __MODULE__
alias ExTTRPGDev.Characters.Metadata
alias ExTTRPGDev.RuleSystems

@moduledoc """
Definition of an individual character
"""
defstruct [:name, :ability_scores, :metadata]

@doc """
Load a character from json representation
"""
def from_json!(character_json) when is_bitstring(character_json) do
character_json
|> Poison.decode!(
as: %Character{
metadata: %Metadata{
rule_system: %RuleSystems.Metadata{}
}
}
)
end

@doc """
Returns an auto generated character for the system

## Examples
iex> Character.gen_character(rule_system)
%Character{}
"""
def gen_character!(%RuleSystems.RuleSystem{
abilities: %RuleSystems.Abilities{} = abilities,
metadata: %RuleSystems.Metadata{} = rule_system_metadata
}) do
character_name = Faker.Person.name()

%Character{
name: character_name,
ability_scores: RuleSystems.Abilities.gen_scores(abilities),
metadata: %ExTTRPGDev.Characters.Metadata{
slug:
character_name
|> String.downcase()
|> String.replace(~r/[!#$%&()*+,.:;<=>?@\^_`'{|}~-]/, "")
|> String.replace(" ", "_"),
rule_system: rule_system_metadata
}
}
end
end
6 changes: 6 additions & 0 deletions lib/characters/metadata.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
defmodule ExTTRPGDev.Characters.Metadata do
@moduledoc """
Metadata for an individual charater
"""
defstruct [:slug, :rule_system]
end
233 changes: 11 additions & 222 deletions lib/cli.ex
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
# credo:disable-for-this-file Credo.Check.Warning.IoInspect
defmodule ExTTRPGDev.CLI do
alias ExTTRPGDev.Dice
alias ExTTRPGDev.RuleSystems
alias ExTTRPGDev.RuleSystems.Abilities
alias ExTTRPGDev.RuleSystems.Languages
alias ExTTRPGDev.RuleSystems.Skills
alias ExTTRPGDev.CustomParsers
alias ExTTRPGDev.CLI.Generate
alias ExTTRPGDev.CLI.Roll
alias ExTTRPGDev.CLI.RuleSystems

@moduledoc """
The CLI for the project
Expand All @@ -21,143 +18,27 @@ defmodule ExTTRPGDev.CLI do
about: "Utility for playing tabletop role-playing games.",
allow_unknown_args: false,
parse_double_dash: true,
subcommands: [
roll: [
name: "roll",
about: "Roll some dice",
args: [
dice: [
value_name: "DICE",
help:
"Dice in the format of xdy wherein x is the number of dice, y is the number of sides the dice should have",
required: true,
parser: &CustomParsers.dice_parser(&1)
]
]
],
list_systems: [
name: "list-systems",
about: "List systems that are setup to be used with ExTTRPGDev"
],
system: [
name: "system",
about: "Top level command fo systems",
subcommands: [
gen: [
name: "gen",
about: "Used for generating things for the system",
subcommands: [
stat_block: [
name: "stat-block",
about: "Generate stat blocks for characters of the system",
args: [
system: [
value_name: "SYSTEM",
help: "A supported system, e.g. dnd5e",
required: true,
parser: :string
]
]
],
character: [
name: "character",
about: "Generate characters for system",
args: [
system: [
value_name: "SYSTEM",
help: "A supported system, e.g. dnd5e",
required: true,
parser: :string
]
]
]
]
],
show: [
name: "show",
about: "Used for showing information about the rule system",
subcommands: [
abilities: [
name: "abilities",
about: "Show the rule systems character abilities",
args: [
system: [
value_name: "SYSTEM",
help: "A supported system, e.g. dnd5e",
required: true,
parser: :string
]
]
],
languages: [
name: "languages",
about: "Show the rule systems languages",
args: [
system: [
value_name: "SYSTEM",
help: "A supported system, e.g. dnd5e",
required: true,
parser: :string
]
]
],
metadata: [
name: "metadata",
about: "Show system metadata",
args: [
system: [
value_name: "SYSTEM",
help: "A supported system, e.g. dnd5e",
required: true,
parser: :string
]
]
],
skills: [
name: "skills",
about: "Show rule system skills",
args: [
system: [
value_name: "SYSTEM",
help: "A supported system, e.g. dnd5e",
required: true,
parser: :string
]
]
]
]
]
]
],
gen: [
name: "gen",
about: "system agnostic generation helpers",
subcommands: [
name: [
name: "name",
about: "Generate a random name"
]
]
]
]
subcommands:
Roll.commands() ++
RuleSystems.commands() ++
Generate.commands()
)

case Optimus.parse!(optimus, argv) do
%{args: %{}} ->
Optimus.parse!(optimus, ["--help"])

{[:roll], parse_result} ->
handle_roll(parse_result)
Roll.handle(parse_result)

{[:list_systems], _} ->
RuleSystems.list_systems()
|> IO.inspect(label: "Configured Systems")
RuleSystems.handle_list_systems()

{[:system | sub_commands], parse_result} ->
handle_system_subcommands(sub_commands, parse_result)
RuleSystems.handle_system_subcommands(sub_commands, parse_result)

{[:gen | sub_commands], _} ->
handle_generate_subcommands(sub_commands)
Generate.handle_generate_subcommands(sub_commands)

{unhandled, _parse_result} ->
str_command =
Expand All @@ -169,96 +50,4 @@ defmodule ExTTRPGDev.CLI do
raise "Unhandled CLI command `#{str_command}`, if you are seeing this error please report the issue"
end
end

def handle_roll(%Optimus.ParseResult{args: %{dice: dice}}) do
dice
|> Dice.multi_roll!()
|> Enum.each(fn {dice_spec, results} ->
IO.inspect(results, label: dice_spec, charlists: :as_lists)
end)
end

def handle_system_subcommands([command | subcommands], %Optimus.ParseResult{
args: %{system: system}
}) do
loaded_system =
system
|> RuleSystems.assert_configured!()
|> RuleSystems.load_system!()

case command do
:gen ->
handle_system_generation_subcommands(subcommands, loaded_system)

:show ->
handle_system_show_subcommands(subcommands, loaded_system)
end
end

def handle_system_generation_subcommands(
[command | _subcommands],
%RuleSystems.RuleSystem{} = system
) do
case command do
:stat_block ->
RuleSystems.RuleSystem.gen_ability_scores_assigned(system)
|> IO.inspect()

:character ->
character = RuleSystems.RuleSystem.gen_character!(system)
IO.puts("-- Name: #{character.name}")

Enum.each(character.ability_scores, fn {ability, scores} ->
IO.puts("#{ability}: #{Enum.sum(scores)}")
end)
end
end

def handle_system_show_subcommands(
[command | _subcommands],
%RuleSystems.RuleSystem{} = system
) do
case command do
:abilities ->
show_abilities(system)

:languages ->
show_languages(system)

:metadata ->
Map.get(system, :metadata)
|> IO.inspect()

:skills ->
show_skills(system)
end
end

def handle_generate_subcommands([command | _subcommands]) do
case command do
:name ->
IO.inspect(Faker.Person.name())
end
end

def show_abilities(%RuleSystems.RuleSystem{abilities: %Abilities{specs: specs}}) do
Enum.each(specs, fn %Abilities.Spec{name: name, abbreviation: abbr} ->
IO.puts("(#{abbr}) #{name}")
end)
end

def show_languages(%RuleSystems.RuleSystem{languages: languages}) do
Enum.each(languages, fn %Languages.Language{name: name, script: script} ->
IO.puts("Name: #{name}, Script: #{script}")
end)
end

def show_skills(%RuleSystems.RuleSystem{skills: skills} = system) do
Enum.each(skills, fn %Skills.Skill{name: name, modifying_stat: mod_stat} ->
%Abilities.Spec{abbreviation: abbr} =
RuleSystems.RuleSystem.get_spec_by_name(system, mod_stat)

IO.puts("(#{abbr}) #{name}")
end)
end
end
4 changes: 2 additions & 2 deletions lib/custom_parsers.ex → lib/cli/custom_parsers.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
defmodule ExTTRPGDev.CustomParsers do
defmodule ExTTRPGDev.CLI.CustomParsers do
@moduledoc """
Custom parsers to be used with Optimus args :parse
"""
Expand All @@ -8,7 +8,7 @@ defmodule ExTTRPGDev.CustomParsers do

## Examples

iex> ExTTRPGDev.CustomParsers.dice_parser("3d4, 1d10,2d20")
iex> ExTTRPGDev.CLI.CustomParsers.dice_parser("3d4, 1d10,2d20")
{:ok, ["3d4", "1d10", "2d20"]}
"""
def dice_parser(arg) when is_bitstring(arg) do
Expand Down
Loading
Loading