Skip to content

Commit

Permalink
Merge pull request #31 from TTRPG-Dev/qmalcolm--reogranize-modules
Browse files Browse the repository at this point in the history
Refactor modules to make them more consistent and split out CLI
  • Loading branch information
QMalcolm authored Dec 8, 2024
2 parents 0ab307f + 83e02df commit 267b236
Show file tree
Hide file tree
Showing 13 changed files with 405 additions and 309 deletions.
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

0 comments on commit 267b236

Please sign in to comment.